参考书目:《HTML5 Canvas核心技术 图形、动画与游戏开发》
使用浮云DIV元素来实现橡皮筋式选取框
1-9.html
<!DOCTYPE html>
<html>
<head>
<title>
Rubberbands with getImageData() and putImageData()
</title>
<style>
body {
background: rgba(100, 145, 250, 0.3);
}
#canvas {
margin-left: 20px;
margin-right: 0;
margin-bottom: 20px;
border: thin solid #aaaaaa;
cursor: crosshair;
}
#controls {
margin: 20px 0px 20px 20px;
}
</style>
</head>
<body>
<div id='controls'>
<input type='button' id='resetButton' value='Reset'/>
</div>
<canvas id='canvas' width='800' height='520'>
Canvas not supported
</canvas>
<script src='1-10.js'></script>
</body>
</html>
1-10.js
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
resetButton = document.getElementById('resetButton'),
image = new Image(),
imageData,
imageDataCopy = context.createImageData(canvas.width, canvas.height),
mousedown = {},
rubberbandRectangle = {},
dragging = false;
function windowToCanvas(canvas, x, y) {
var canvasRectangle = canvas.getBoundingClientRect();
return {
x: (x - canvasRectangle.left)*(canvas.width / canvasRectangle.width),
y: (y - canvasRectangle.top) *(canvas.height / canvasRectangle.height)
};
}
function copyCanvasPixels() {
var i=0;
for (i=0; i < 3; i++) {
imageDataCopy.data[i] = imageData.data[i];
}
for (i=3; i < imageData.data.length - 4; i+=4) {
imageDataCopy.data[i] = imageData.data[i] / 2; // Alpha: more transparent
imageDataCopy.data[i+1] = imageData.data[i+1]; // Red
imageDataCopy.data[i+2] = imageData.data[i+2]; // Green
imageDataCopy.data[i+3] = imageData.data[i+3]; // Blue
}
}
function captureCanvasPixels() {
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
copyCanvasPixels();
}
function restoreRubberbandPixels() {
var deviceWidthOverCSSPixels = imageData.width / canvas.width,
deviceHeightOverCSSPixels = imageData.height / canvas.height;
context.putImageData(imageData, 0, 0);
context.putImageData(imageDataCopy, 0, 0,
(rubberbandRectangle.left + context.lineWidth),
(rubberbandRectangle.top + context.lineWidth),
(rubberbandRectangle.width - 2*context.lineWidth) * deviceWidthOverCSSPixels,
(rubberbandRectangle.height - 2*context.lineWidth) * deviceHeightOverCSSPixels);
}
function setRubberbandRectangle(x, y) {
rubberbandRectangle.left = Math.min(x, mousedown.x);
rubberbandRectangle.top = Math.min(y, mousedown.y);
rubberbandRectangle.width = Math.abs(x - mousedown.x),
rubberbandRectangle.height = Math.abs(y - mousedown.y);
}
function drawRubberband() {
var deviceWidthOverCSSPixels = imageData.width / canvas.width,
deviceHeightOverCSSPixels = imageData.height / canvas.height;
context.strokeRect(rubberbandRectangle.left + context.lineWidth,
rubberbandRectangle.top + context.lineWidth,
rubberbandRectangle.width - 2*context.lineWidth,
rubberbandRectangle.height - 2*context.lineWidth);
}
function rubberbandStart(x, y) {
mousedown.x = x;
mousedown.y = y;
rubberbandRectangle.left = mousedown.x;
rubberbandRectangle.top = mousedown.y;
rubberbandRectangle.width = 0;
rubberbandRectangle.height = 0;
dragging = true;
captureCanvasPixels();
}
function rubberbandStretch(x, y) {
if (rubberbandRectangle.width > 2*context.lineWidth &&
rubberbandRectangle.height > 2*context.lineWidth) {
if (imageData !== undefined) {
restoreRubberbandPixels();
}
}
setRubberbandRectangle(x, y);
if (rubberbandRectangle.width > 2*context.lineWidth &&
rubberbandRectangle.height > 2*context.lineWidth) {
drawRubberband();
}
};
function rubberbandEnd() {
context.putImageData(imageData, 0, 0);
context.drawImage(canvas,
rubberbandRectangle.left + context.lineWidth*2,
rubberbandRectangle.top + context.lineWidth*2,
rubberbandRectangle.width - 4*context.lineWidth,
rubberbandRectangle.height - 4*context.lineWidth,
0, 0, canvas.width, canvas.height);
dragging = false;
imageData = undefined;
}
canvas.onmousedown = function (e) {
var loc = windowToCanvas(canvas, e.clientX, e.clientY);
e.preventDefault();
rubberbandStart(loc.x, loc.y);
};
canvas.onmousemove = function (e) {
var loc;
if (dragging) {
loc = windowToCanvas(canvas, e.clientX, e.clientY);
rubberbandStretch(loc.x, loc.y);
}
}
canvas.onmouseup = function (e) {
rubberbandEnd();
};
image.src = 'arch.png';
image.onload = function () {
context.drawImage(image, 0, 0, canvas.width, canvas.height);
};
resetButton.onclick = function(e) {
context.clearRect(0, 0,
canvas.width, canvas.height);
context.drawImage(image, 0, 0, canvas.width, canvas.height);
};
context.strokeStyle = 'navy';
context.lineWidth = 1.0;
效果如图: