初学Canvas,用canvas做了简单的画图工具体会并熟悉了一下大致的实现方案。开发完也算是基本了解canvas的用法了。
HTML部分:
<div class="app">
<div class="menu">
<div class="toollist">
<button class="menu-item" style="width: fit-content;" onclick="clearCanvas()">clear</button>
<button class="menu-item" onclick="restoreMouse()">
<svg>//图标
</svg>
</button>
<button class="menu-item" onclick="pencilDraw()">
<svg>//图标
</svg>
</button>
<button class="menu-item" onclick="lineDraw()">
<svg>
</svg>
</button>
<button class="menu-item" onclick="saveCanvas()">
<svg>
</svg>
</button>
<button class="menu-item" onclick="useEraser()">
<svg>
</svg>
</button>
<button class="menu-item" onclick="RectDraw()">
<svg>
</svg></button>
<button class="menu-item" onclick="circleDraw()">
<svg>
</svg>
</button>
<button class="menu-item" onclick="insertText()">A</button>
</div>
<div>
<input type="color" style="margin-top: 10px;" onchange="handleColorChange(this)">
</div>
</div>
<div style="background-color: #fff; position: relative;" class="canvas-area">
<canvas id="canvas" width="1000" height="1000"></canvas>
</div>
<!-- <input type="text" style="border: 1px dashed #ccc; position:absolute;top:0;left:10%;outline:none"> -->
</div>
JS部分:
根据选择的画笔工具分别进行处理,实际上直线,圆,矩形的绘画代码除了使用的方法不同外,唯一的小难点可能就是没办法在画布上重复地绘画,此时需要用到两个方法来实现:
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
ctx.getImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
get方法用来保存当前画布的信息,在onmouseup时,保存此次操作后的画布状态。而put方法则在每次落笔清除绘画轨迹后,将之前保存的数据进行还原,从而实现多次重复绘画的效果。
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var drawdown = false;
var startPointX, startPointY;
var toolcontrol = {
pencil: false,
line: false,
}
var convasData = null;
var drawcolor = "#000";
var curtool;
var textvalue;
function setUsingTool(tool) {
for (const key in toolcontrol) {
toolcontrol[key] = false;
}
toolcontrol[tool] = true;
curtool = tool;
// curtool=='line'?
// ctx=canvas2.getContext('2d'):
// ctx=canvas.getContext('2d');
}
//function clearCanvas() {
// ctx.clearRect(0, 0, 1000, 1000)
//}
function drawToolHandler(tool) {
canvas.addEventListener('mousedown', handleMouseDown);
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('mouseup', handleMouseUp);
}
var handleMouseDown = (e) => {
switch (curtool) {
case 'pencil':
drawdown = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
break;
case 'line':
case 'rect':
case 'ring':
case 'text':
drawdown = true;
startPointX = e.offsetX;
startPointY = e.offsetY;
break;
case 'eraser':
drawdown = true;
break;
default: return;
}
}
var handleMouseMove = (e) => {
switch (curtool) {
case 'pencil':
if (drawdown) {
ctx.lineTo(e.offsetX, e.offsetY)
ctx.strokeStyle = drawcolor.toString();
ctx.stroke();
}
break;
case 'line':
if (drawdown) {
ctx.beginPath();
ctx.clearRect(0, 0, 1000, 1000);
if (convasData != null) {
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
}
ctx.moveTo(startPointX, startPointY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.closePath();
ctx.strokeStyle = drawcolor;
ctx.stroke();
}
break;
case 'rect':
if (drawdown) {
ctx.beginPath();
ctx.clearRect(0, 0, 1000, 1000);
if (convasData != null) {
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
}
ctx.strokeStyle = drawcolor;
ctx.strokeRect(startPointX, startPointY, e.offsetX - startPointX, e.offsetY - startPointY);
ctx.closePath();
}
break;
case 'ring':
if (drawdown) {
ctx.beginPath();
ctx.clearRect(0, 0, 1000, 1000);
if (convasData != null) {
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
}
ctx.strokeStyle = drawcolor;
ctx.arc(startPointX, startPointY, (e.offsetY - startPointY) / 2, 0, 2 * Math.PI, false);
ctx.stroke()
ctx.closePath();
}
break;
case 'text':
if (drawdown) {
ctx.beginPath();
ctx.clearRect(0, 0, 1000, 1000);
if (convasData != null) {
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
}
ctx.strokeStyle = '#000';
ctx.strokeRect(startPointX, startPointY, e.offsetX - startPointX, e.offsetY - startPointY);
ctx.closePath();
}
case 'eraser':
if (drawdown) {
ctx.beginPath();
ctx.moveTo(startPointX, startPointY);
ctx.clearRect(e.offsetX, e.offsetY, 50, 50);
}
break;
default: return;
}
}
var handleMouseUp = (e) => {
if (curtool == 'text'&&e.offsetX - startPointX>=10&&e.offsetY - startPointY>=10) {
// ctx.clearRect(0, 0, 1000, 1000);
let input = document.createElement('input');
let canvasArea = document.getElementsByClassName('canvas-area')[0];
canvasArea.appendChild(input);
input.style.position = "absolute";
input.style.left = `${startPointX}px`;
input.style.top = `${startPointY}px`;
input.style.width = `${e.offsetX - startPointX}px`;
input.style.height = `${e.offsetY - startPointY}px`;
input.style.fontSize =`${parseInt(input.style.height)/2}px`;
input.style.border = "2px dashed #ccc";
input.style.outline = 'none'
input.addEventListener('input',(e)=>{
textvalue=e.target.value
})
input.addEventListener('blur',()=>{
ctx.clearRect(0, 0, 1000, 1000);
if (convasData != null) {
ctx.putImageData(convasData, 0, 0, 0, 0, canvas.offsetWidth, canvas.offsetHeight);
}
ctx.font=`${parseInt(input.style.height)/2}px sans-serif`;
ctx.fillText(textvalue,parseInt(input.style.left)+20,parseInt(input.style.top)+0.6*parseInt(input.style.height));
canvasArea.removeChild(input);
convasData = ctx.getImageData(0, 0, canvas.offsetWidth, canvas.offsetHeight);
})
drawdown = false;
} else {
convasData = ctx.getImageData(0, 0, canvas.offsetWidth, canvas.offsetHeight);
drawdown = false;
}
}
function restoreMouse() {
canvas.removeEventListener('mousedown', handleMouseDown);
canvas.removeEventListener('mousemove', handleMouseMove);
canvas.removeEventListener('mouseup', handleMouseUp);
}
function pencilDraw() {
setUsingTool('pencil');
drawToolHandler('pencil');
}
function lineDraw() {
setUsingTool('line');
drawToolHandler('line');
}
function useEraser() {
setUsingTool('eraser');
drawToolHandler('eraser');
}
function RectDraw() {
setUsingTool('rect');
drawToolHandler('rect');
}
function circleDraw() {
setUsingTool('ring');
drawToolHandler('ring');
}
function insertText() {
setUsingTool('text');
drawToolHandler('text');
}
function handleColorChange(e) {
console.log(e.value);
drawcolor = e.value
}
function saveCanvas() {
var a = document.createElement("a");
a.href = canvas.toDataURL();
var fileName = prompt("命名你的图画");
a.download = fileName || "canvaspic"
a.click();
}
其中插入文本相对特殊一些,需要先在页面根据鼠标移动画出一个矩形,鼠标松开时,创建一个矩形大小的input,输入文字且失去焦点后,将input输入的值画在canvas上。
效果: