放大鼠标框选区域的图片
使用 Canvas 显示图片,通过鼠标选中 Canvas 内的一个矩形区域,松开鼠标后将该矩形内的内容以最适应 Canvas 框大小的方式来显示。基于 Vue 的写法。
示例:
1.加入 Canvas 元素
<div id="canvasContainer" style="width:100%;text-align:center;overflow:auto">
<canvas id="canvas" width="1" height="1" tabindex="1">
Sorry, your browser does not support HTML5 Canvas functionality which is
required for this application.
</canvas>
</div>
2.声明全局变量
data() {
return {
zoomRate: 1,
// canvas拖拽放大缩小
canvas: {},
context: {},
offscreenCanvas: {},
offscreenContext: {},
mousedown: {},
rubberbandRectangle: {},
dragging: false,
scaleRate: 1,
mousemove: {},
};
}
3.在页面的 dom 渲染完成做事件监听
mounted() {
// 初始化canvas对象
this.canvas = document.getElementById("canvas");
this.context = this.canvas.getContext("2d");
this.offscreenCanvas = document.createElement("canvas");
this.offscreenContext = this.offscreenCanvas.getContext("2d");
this.canvas.onmousedown = (e) => { // 开始框选
let loc = this.windowToCanvas(this.canvas, e.clientX, e.clientY); //获取鼠标点击在canvas的坐标
e.preventDefault();
this.mousedown.x = loc.x;
this.mousedown.y = loc.y;
this.rubberbandRectangle.left = this.mousedown.x;
this.rubberbandRectangle.top = this.mousedown.y;
this.dragging = true;
};
this.canvas.onmousemove = (e) => { // 框选中
let loc = {};
if (this.dragging) {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.drawImage(
this.offscreenCanvas,
0,
0,
this.canvas.width,
this.canvas.height
); //把离屏canvas上的数据复制到当前canvas
loc = this.windowToCanvas(this.canvas, e.clientX, e.clientY);
this.rubberbandStretch(loc.x, loc.y); //计算出选中的矩形坐标
} else {
// 记录非点击状态下鼠标的位置,为定点缩放做准备
this.mousemove = this.windowToCanvas(this.canvas, e.clientX, e.clientY);
}
};
this.canvas.onmouseup = (e) => { // 结束框选
let loc = this.windowToCanvas(this.canvas, e.clientY, e.clientY);
this.rubberbandEnd(loc.x, loc.y); //鼠标抬起 开始从离屏canvas复制数据
};
}
4.事件处理函数
methods: {
drawImage() {
const canvasContainer = document.getElementById("canvasContainer");
if (canvasContainer && this.canvas) {
if (this.context) {
const img = new Image();
img.src = this.imageData;
img.onload = () => {
// 获得body当前的尺寸,计算出缩放比例,对高度做限制
// 使用原尺寸高度,在默认状态下会出现上下滚动条 canvasContainer.offsetHeight,略丑
const heightScaleRate =
(canvasContainer.offsetHeight - 5) / img.height;
const widthScaleRate =
(canvasContainer.offsetWidth - 5) / img.width;
// 选取比率小的,以防超过边界出现滚动条
this.scaleRate =
heightScaleRate > widthScaleRate
? widthScaleRate
: heightScaleRate;
this.context.scale(this.scaleRate, this.scaleRate);
this.canvas.width = Math.round(
img.width * this.scaleRate * this.zoomRate
);
this.canvas.height = Math.round(
img.height * this.scaleRate * this.zoomRate
);
this.context.beginPath();
this.context.drawImage(
img,
0,
0,
this.canvas.width,
this.canvas.height
);
this.context.stroke();
this.offscreenCanvas.width = img.width;
this.offscreenCanvas.height = img.height;
this.offscreenContext.drawImage(
img,
0,
0,
this.offscreenCanvas.width,
this.offscreenCanvas.height
);
};
}
}
},
windowToCanvas(canvas, x, y) {
let bbox = canvas.getBoundingClientRect();
return {
x: x - bbox.left,
y: y - bbox.top,
};
},
rubberbandStretch(x, y) {
this.rubberbandRectangle.left = Math.min(x, this.mousedown.x);
this.rubberbandRectangle.top = Math.min(y, this.mousedown.y);
this.rubberbandRectangle.width = Math.abs(x - this.mousedown.x);
this.rubberbandRectangle.height = Math.abs(y - this.mousedown.y);
this.context.fillStyle = "rgba(96,98,102,0.3)";
this.context.fillRect(
this.rubberbandRectangle.left,
this.rubberbandRectangle.top,
this.rubberbandRectangle.width,
this.rubberbandRectangle.height
);
},
rubberbandEnd(x, y) {
if (
x == this.rubberbandRectangle.left ||
y == this.rubberbandRectangle.top
) {
this.dragging = false;
return;
}
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 获取在原图里的尺寸
this.canvas.width =
this.rubberbandRectangle.width / this.scaleRate / this.zoomRate;
this.canvas.height =
this.rubberbandRectangle.height / this.scaleRate / this.zoomRate;
this.context.drawImage(
this.offscreenCanvas,
this.rubberbandRectangle.left / this.scaleRate / this.zoomRate,
this.rubberbandRectangle.top / this.scaleRate / this.zoomRate,
this.rubberbandRectangle.width / this.scaleRate / this.zoomRate,
this.rubberbandRectangle.height / this.scaleRate / this.zoomRate,
0,
0,
this.rubberbandRectangle.width / this.scaleRate / this.zoomRate,
this.rubberbandRectangle.height / this.scaleRate / this.zoomRate
);
var base64Img = this.canvas.toDataURL("image/jpg");
this.imageData = base64Img;
this.drawImage();
this.dragging = false;
},
}
可通过按钮、框选、滚轮滚动来放大缩小图片的示例: