返回
Canvas 绘图工具集锦:标记、缩放、位移和历史保存
前端
2024-01-29 22:53:18
在开发过程中,我花了大量时间来寻找一种可以在 Canvas 上实现图像标记、缩放、位移和历史状态保存的解决方案。网上关于这方面的资料十分稀少,所以我只能自己慢慢地推导出来。
让我们以横坐标为例,首先,我制作了两个相同的元素,并在它们上标记了坐标,然后设置容器属性 overflow:hidden 来隐藏溢出内容。
.container {
overflow: hidden;
}
接着,我对比了原始大小和放大 3 倍后的结果,发现缩放后的元素的宽度是原始宽度的三倍,而左边隐藏的内容的宽度是原始宽度的两倍。
原始宽度:100px
缩放后宽度:300px
隐藏内容宽度:200px
根据这些信息,我推导出了下面的公式:
隐藏内容宽度 = 缩放后宽度 - 原始宽度
同样的道理,我还推导出以下公式:
隐藏内容高度 = 缩放后高度 - 原始高度
这些公式可以帮助我计算出隐藏内容的宽度和高度,以便在缩放时正确地定位标记。
在实现了缩放功能之后,我又继续实现了标记、位移和历史状态保存功能。整个过程虽然有些复杂,但我最终还是成功了。
现在,我将把这些代码分享给大家。我希望它们能帮助你们在开发中实现类似的功能。
// Canvas 初始化
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 图片加载
const image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0);
};
image.src = 'image.png';
// 标记工具
const markerTool = {
isDrawing: false,
startX: 0,
startY: 0,
endX: 0,
endY: 0,
startDrawing(e) {
this.isDrawing = true;
this.startX = e.clientX;
this.startY = e.clientY;
},
moveDrawing(e) {
if (!this.isDrawing) {
return;
}
this.endX = e.clientX;
this.endY = e.clientY;
ctx.strokeStyle = 'red';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(this.startX, this.startY);
ctx.lineTo(this.endX, this.endY);
ctx.stroke();
},
endDrawing() {
this.isDrawing = false;
}
};
// 缩放工具
const zoomTool = {
scaleFactor: 1,
zoomIn() {
this.scaleFactor *= 2;
ctx.scale(2, 2);
},
zoomOut() {
this.scaleFactor /= 2;
ctx.scale(0.5, 0.5);
}
};
// 位移工具
const panTool = {
isDragging: false,
startX: 0,
startY: 0,
startDragging(e) {
this.isDragging = true;
this.startX = e.clientX;
this.startY = e.clientY;
},
moveDragging(e) {
if (!this.isDragging) {
return;
}
const dx = e.clientX - this.startX;
const dy = e.clientY - this.startY;
ctx.translate(dx, dy);
this.startX = e.clientX;
this.startY = e.clientY;
},
endDragging() {
this.isDragging = false;
}
};
// 历史状态保存
const history = [];
const saveState() {
history.push(canvas.toDataURL());
}
const restoreState() {
if (history.length > 0) {
const dataURL = history.pop();
const image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0);
};
image.src = dataURL;
}
}
// 事件监听器
canvas.addEventListener('mousedown', markerTool.startDrawing);
canvas.addEventListener('mousemove', markerTool.moveDrawing);
canvas.addEventListener('mouseup', markerTool.endDrawing);
canvas.addEventListener('mousewheel', zoomTool.zoomIn);
canvas.addEventListener('mousewheel', zoomTool.zoomOut);
canvas.addEventListener('mousedown', panTool.startDragging);
canvas.addEventListener('mousemove', panTool.moveDragging);
canvas.addEventListener('mouseup', panTool.endDragging);
document.getElementById('save-button').addEventListener('click', saveState);
document.getElementById('restore-button').addEventListener('click', restoreState);
我希望这些代码能帮助你们开发出更出色的应用程序。