/*拖动的实现,其实就是把所有绘制的对象封装成一个对象,
1、判断当前鼠标的位置,是否在此图形的路径内,如果在路径内,则保存当前的对象,
2、拖动鼠标时,改变其所在位置的值,充分利用了对象的指针的特点,这里可以考虑把对象放置在一个缓存中,而不是把整个面板放在一个缓存中进行重新绘制
3、释放鼠标时,重绘所有对象
*/
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
eraseAllButton = document.getElementById('eraseAllButton'),//擦除
strokeStyleSelect = document.getElementById('strokeStyleSelect'),//描边颜色
startAngleSelect = document.getElementById('startAngleSelect'),//绘制角度
fillStyleSelect = document.getElementById('fillStyleSelect'),//填充颜色
fillCheckbox = document.getElementById('fillCheckbox'),//是否填充
editCheckbox = document.getElementById('editCheckbox'),//是否能拖动
sidesSelect = document.getElementById('sidesSelect'),
drawingSurfaceImageData,
mousedown = {},
rubberbandRect = {},
dragging = false,
draggingOffsetX,
draggingOffsetY,
sides = 8,
startAngle = 0,
guidewires = true,
editing = false,
polygons = [];
// Functions..........................................................
function drawGrid(color, stepx, stepy) {//画网格线
context.save()
context.shadowColor = undefined;
context.shadowBlur = 0;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.strokeStyle = color;
context.fillStyle = '#ffffff';
context.lineWidth = 0.5;
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();
for (var i = stepx + 0.5; i < context.canvas.width; i += stepx) {
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
}
context.stroke();
context.beginPath();
for (var i = stepy + 0.5; i < context.canvas.height; i += stepy) {
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
}
context.stroke();
context.restore();
}
function windowToCanvas(x, y) {//转换坐标
var bbox = canvas.getBoundingClientRect();
return { x: x - bbox.left * (canvas.width / bbox.width),
y: y - bbox.top * (canvas.height / bbox.height)
};
}
// Save and restore drawing surface...................................
function saveDrawingSurface() {
drawingSurfaceImageData = context.getImageData(0, 0,
canvas.width,
canvas.height);
}
function restoreDrawingSurface() {
context.putImageData(drawingSurfaceImageData, 0, 0);
}
// Draw a polygon.....................................................
function drawPolygon(polygon) {
context.beginPath();
polygon.createPath(context);
polygon.stroke(context);
if (fillCheckbox.checked) {
polygon.fill(context);
}
}
// Rubberbands........................................................
function updateRubberbandRectangle(loc) {
rubberbandRect.width = Math.abs(loc.x - mousedown.x);
rubberbandRect.height = Math.abs(loc.y - mousedown.y);
if (loc.x > mousedown.x) rubberbandRect.left = mousedown.x;
else rubberbandRect.left = loc.x;
if (loc.y > mousedown.y) rubberbandRect.top = mousedown.y;
else rubberbandRect.top = loc.y;
}
function drawRubberbandShape(loc, sides, startAngle) {
var polygon = new Polygon(mousedown.x, mousedown.y,
rubberbandRect.width,
parseInt(sidesSelect.value),
(Math.PI / 180) * parseInt(startAngleSelect.value),
context.strokeStyle,
context.fillStyle,
fillCheckbox.checked);
drawPolygon(polygon);
console.log(dragging);
if (!dragging) {
polygons.push(polygon);
}
}
function updateRubberband(loc, sides, startAngle) {
updateRubberbandRectangle(loc);
drawRubberbandShape(loc, sides, startAngle);
}
// Guidewires.........................................................
function drawHorizontalLine (y) {
context.beginPath();
context.moveTo(0,y+0.5);
context.lineTo(context.canvas.width,y+0.5);
context.stroke();
}
function drawVerticalLine (x) {
context.beginPath();
context.moveTo(x+0.5,0);
context.lineTo(x+0.5,context.canvas.height);
context.stroke();
}
function drawGuidewires(x, y) {//画引导线
context.save();
context.strokeStyle = 'rgba(0,0,230,0.4)';
context.lineWidth = 0.5;
drawVerticalLine(x);
drawHorizontalLine(y);
context.restore();
}
function drawPolygons() {
polygons.forEach( function (polygon) {
drawPolygon(polygon);
});
}
// Dragging...........................................................
//保存原有图片内容,记录开始坐标
function startDragging(loc) {
saveDrawingSurface();
mousedown.x = loc.x;
mousedown.y = loc.y;
}
function startEditing() {
canvas.style.cursor = 'pointer';
editing = true;
}
function stopEditing() {
canvas.style.cursor = 'crosshair';
editing = false;
}
// Event handlers.....................................................
canvas.onmousedown = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
e.preventDefault(); // prevent cursor change
if (editing) {//关键是这里,当鼠标按下时,为所有缓存起来的图形重绘路径区域,但并不描边,然后判断,鼠标在哪个路径下。这是一个封装路径
polygons.forEach( function (polygon) {
polygon.createPath(context);
if (context.isPointInPath(loc.x, loc.y)) {//这处的鼠标坐标一定要进行转换,另外上面创建的路径可以不调用closePath(),默认好像是有个连接,closePath(),只不过是多划一条线
startDragging(loc);
dragging = polygon;//重新绘制时,只改变这个被选中图形的坐标即可
draggingOffsetX = loc.x - polygon.x;
draggingOffsetY = loc.y - polygon.y;
return;
}
});
}
else {
startDragging(loc);//画线
dragging = true;
}
};
canvas.onmousemove = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
e.preventDefault(); // prevent selections
if (editing && dragging) {
dragging.x = loc.x - draggingOffsetX;//见上面注释
dragging.y = loc.y - draggingOffsetY;
context.clearRect(0, 0, canvas.width, canvas.height);
drawGrid('lightgray', 10, 10);
drawPolygons();
}
else {
if (dragging) {
restoreDrawingSurface();
updateRubberband(loc, sides, startAngle);
if (guidewires) {
drawGuidewires(mousedown.x, mousedown.y);
}
}
}
};
canvas.onmouseup = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
dragging = false;
if (editing) {
}
else {
restoreDrawingSurface();
updateRubberband(loc);
}
};
eraseAllButton.onclick = function (e) {
context.clearRect(0, 0, canvas.width, canvas.height);
drawGrid('lightgray', 10, 10);
saveDrawingSurface();
};
strokeStyleSelect.onchange = function (e) {
context.strokeStyle = strokeStyleSelect.value;
};
fillStyleSelect.onchange = function (e) {
context.fillStyle = fillStyleSelect.value;
};
editCheckbox.onchange = function (e) {
if (editCheckbox.checked) {
startEditing();
}
else {
stopEditing();
}
};
// Initialization.....................................................
context.strokeStyle = strokeStyleSelect.value;
context.fillStyle = fillStyleSelect.value;
drawGrid('lightgray', 10, 10);
if (navigator.userAgent.indexOf('Opera') === -1)
context.shadowColor = 'rgba(0, 0, 0, 0.4)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;