最近学习canvas,用canvas做了一个简单的图片编辑器! demo
先看代码
<canvas id="drawingCanvas" width="300", height="300" style="border: 1px solid"></canvas>
<div>
<button onclick="Undo()">撤销</button>
<button onclick="checkRect()">正方形</button>
<button onclick="checkCircle()">圆形</button>
<button onclick="checkArrow()">箭头</button>
<button onclick="checkLine()">画笔</button>
</div>
var canvas;
var context;
var startX;
var startY;
var endX;
var endY;
var pattern = 'pen';
var memory = [];
var imageSrc = 'http://7sbq8w.com1.z0.glb.clouddn.com/box.png';
var imageObj;
//imageObj = new Image();
//imageObj.src = imageSrc;
// 初始化
window.onload = function() {
// 获取画布
canvas = document.getElementById("drawingCanvas");
context = canvas.getContext("2d");
imageObj = new Image();
imageObj.src = imageSrc;
imageObj.onload = function () {
drawImage();
}
// 画布添加鼠标事件
canvas.onmousedown = startDrawing;
canvas.onmouseup = draw;
canvas.onmouseout = draw;
canvas.onmousemove = strokeConnection;
};
// 记录当前是否在画图
var isDrawing = false;
// 开始画图
function startDrawing(e) {
isDrawing = true;
context.strokeStyle = 'red';
// 把画笔移动到鼠标位置
startX = e.pageX - canvas.offsetLeft;
startY = e.pageY - canvas.offsetTop;
if (pattern == 'arrow') {
beginPoint.x = startX;
beginPoint.y = startY;
} else if (pattern == 'pen') {
memory.push({lineArray: [], pattern: pattern});
} else {
context.moveTo(e.pageX - canvas.offsetLeft, e.pageY - canvas.offsetTop);
}
}
function drawImage() {
if (imageObj.width / imageObj.height > canvas.width / canvas.height) {
context.drawImage(imageObj, 0, 0, canvas.width, imageObj.height * canvas.width / imageObj.width);
} else {
context.drawImage(imageObj, 0, 0, imageObj.width * canvas.height / canvas.height, canvas.height);
}
}
//画图
function draw(e) {
if (isDrawing == true && pattern != 'pen') {
endX = e.pageX - canvas.offsetLeft;
endY = e.pageY - canvas.offsetTop;
if (pattern == 'rect') {
drawRect();
}
if (pattern == 'circle') {
drawArc();
}
if (pattern == 'arrow') {
drawArrow();
}
memory.push({startX: startX, startY: startY, endX: endX, endY: endY, pattern: pattern});
isDrawing = false;
}
if (isDrawing == true && pattern == 'pen') {
isDrawing = false;
}
}
function strokeConnection(e) {
if (isDrawing == true && pattern == 'pen') {
endX = e.pageX - canvas.offsetLeft;
endY = e.pageY - canvas.offsetTop;
drawLine();
memory[memory.length - 1].lineArray.push({startX: startX, startY: startY, endX: endX, endY: endY});
startX = endX;
startY = endY;
}
}
function drawLine(data) {
context.beginPath();
if (data) {
context.moveTo(data.startX, data.startY);
context.lineTo(data.endX, data.endY);
} else {
context.moveTo(startX, startY);
context.lineTo(endX, endY);
}
context.closePath();
context.stroke();
context.restore();
}
function drawArrow(data) {
if (data) {
beginPoint.x = data.startX;
beginPoint.y = data.startY;
stopPoint.x = data.endX;
stopPoint.y = data.endY;
Plot.arrowCoord(beginPoint, stopPoint);
Plot.sideCoord();
Plot.drawArrow();
} else {
stopPoint.x = endX;
stopPoint.y = endY;
Plot.arrowCoord(beginPoint, stopPoint);
Plot.sideCoord();
Plot.drawArrow();
}
}
function drawArc(data) {
if (data) {
var radiusX = (data.endX - data.startX)/2;
var radiusY = (data.endY - data.startY)/2;
ParamEllipse(data.startX + radiusX, data.startY + radiusY, Math.abs(radiusX), Math.abs(radiusY));
} else {
var radiusX = (endX - startX)/2;
var radiusY = (endY - startY)/2;
ParamEllipse(startX + radiusX, startY + radiusY, Math.abs(radiusX), Math.abs(radiusY));
}
}
function drawRect(data) {
context.beginPath();
if (data) {
context.strokeRect(data.startX, data.startY, data.endX - data.startX, data.endY - data.startY);
} else {
context.strokeRect(startX, startY, endX - startX, endY - startY);
}
context.closePath();
context.stroke();
}
// 清除画布
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
// 保存画布
function saveCanvas() {
alert(canvas.toDataURL());
//return canvas.toDataURL();
}
//撤销
function Undo() {
clearCanvas();
drawImage();
var stroke = memory.pop();
if (stroke) {
redraw();
}
}
//重画
function redraw() {
memory.forEach(function (item) {
if (item.pattern == 'rect') {
drawRect(item);
}
if (item.pattern == 'circle') {
drawArc(item);
}
if (item.pattern == 'arrow') {
drawArrow(item);
}
if (item.pattern == 'pen') {
item.lineArray.forEach(function (it) {
drawLine(it);
})
}
})
}
//切换画矩形
function checkRect() {
pattern = 'rect';
}
//切换画圆形
function checkCircle() {
pattern = 'circle';
}
//切换画箭头
function checkArrow() {
pattern = 'arrow';
}
//切换画线
function checkLine() {
pattern = 'pen';
}
//椭圆
function ParamEllipse(x, y, a, b) {
var step = (a > b) ? 1 / a : 1 / b;
context.beginPath();
context.moveTo(x + a, y);
for (var i = 0; i < 2 * Math.PI; i +=step) {
context.lineTo(x + a * Math.cos(i), y + b * Math.sin(i));
}
context.closePath();
context.stroke();
};
//箭头
var beginPoint = {};
var stopPoint = {};
var polygonVertex = [];
var CONST = {
edgeLen: 50,
angle: 25
};
//封装的作图对象
var Plot = {
angle: "",
//在CONST中定义的edgeLen以及angle参数
//短距离画箭头的时候会出现箭头头部过大,修改:
dynArrowSize: function() {
var x = stopPoint.x - beginPoint.x,
y = stopPoint.y - beginPoint.y,
length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
if (length < 250) {
CONST.edgeLen = CONST.edgeLen/2;
CONST.angle = CONST.angle/2;
}
else if(length<500){
CONST.edgeLen=CONST.edgeLen*length/500;
CONST.angle=CONST.angle*length/500;
}
},
//getRadian 返回以起点与X轴之间的夹角角度值
getRadian: function(beginPoint, stopPoint) {
Plot.angle = Math.atan2(stopPoint.y - beginPoint.y, stopPoint.x - beginPoint.x) / Math.PI * 180;
paraDef(50,25);
Plot.dynArrowSize();
},
//获得箭头底边两个点
arrowCoord: function(beginPoint, stopPoint) {
polygonVertex[0] = beginPoint.x;
polygonVertex[1] = beginPoint.y;
polygonVertex[6] = stopPoint.x;
polygonVertex[7] = stopPoint.y;
Plot.getRadian(beginPoint, stopPoint);
polygonVertex[8] = stopPoint.x - CONST.edgeLen * Math.cos(Math.PI / 180 * (Plot.angle + CONST.angle));
polygonVertex[9] = stopPoint.y - CONST.edgeLen * Math.sin(Math.PI / 180 * (Plot.angle + CONST.angle));
polygonVertex[4] = stopPoint.x - CONST.edgeLen * Math.cos(Math.PI / 180 * (Plot.angle - CONST.angle));
polygonVertex[5] = stopPoint.y - CONST.edgeLen * Math.sin(Math.PI / 180 * (Plot.angle - CONST.angle));
},
//获取另两个底边侧面点
sideCoord: function() {
var midpoint = {};
// midpoint.x = polygonVertex[6] - (CONST.edgeLen * Math.cos(Plot.angle * Math.PI / 180));
// midpoint.y = polygonVertex[7] - (CONST.edgeLen * Math.sin(Plot.angle * Math.PI / 180));
midpoint.x=(polygonVertex[4]+polygonVertex[8])/2;
midpoint.y=(polygonVertex[5]+polygonVertex[9])/2;
polygonVertex[2] = (polygonVertex[4] + midpoint.x) / 2;
polygonVertex[3] = (polygonVertex[5] + midpoint.y) / 2;
polygonVertex[10] = (polygonVertex[8] + midpoint.x) / 2;
polygonVertex[11] = (polygonVertex[9] + midpoint.y) / 2;
},
//画箭头
drawArrow: function() {
context.beginPath();
context.fillStyle = 'red';
context.moveTo(polygonVertex[0], polygonVertex[1]);
context.lineTo(polygonVertex[2], polygonVertex[3]);
context.lineTo(polygonVertex[4], polygonVertex[5]);
context.lineTo(polygonVertex[6], polygonVertex[7]);
context.lineTo(polygonVertex[8], polygonVertex[9]);
context.lineTo(polygonVertex[10], polygonVertex[11]);
context.closePath();
context.fill();
}
};
//自定义参数
function paraDef(edgeLen, angle) {
CONST.edgeLen = edgeLen;
CONST.angle = angle;
}
图片编辑器的主要步骤: 1.创建画布; 2.监听鼠标事件获取位置坐标; 3.画线,画正方形,画圆,画箭头的基础方法; 4.撤销 5.保存
这里主要说一下撤销的实现,其实就是创建一个数组,保存每次编辑的坐标路径,当点击撤销时,清空画布,pop出数组的最新记录,然后根据记忆的数组路径重新画图。