如何解决HTML5 Canvas Color Picker Bug - When a new color is selected, color property is instantly updated on all objects in stroke history array
我正在使用 HTML5 Canvas 在 Javascript 中开发一个简单的绘图应用程序,并在实现颜色选择器后遇到了一个奇怪的错误。
对于撤消/重做功能,每个笔划都被记录为一个包含点坐标数组的对象以及一个包含“颜色”和“宽度”等属性的 BrushInfo 对象。当画布撤消或重做时,它会被清除,然后通过循环遍历每个笔划中的点并使用该信息重绘它们来重绘。
但是,每次选择新颜色时,它都会立即更新历史数组中每个笔画对象中每个笔刷信息对象的“颜色”属性。结果是,当您按 ctrl+z 时,画布上的所有笔划都以最近选择的颜色重新绘制。
I've recreated it in CodePen so you can try it out.
// Set up canvas
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 400 * 2;
canvas.height = 400 * 2;
ctx.scale(2,2);
ctx.fillStyle = "#000";
const colorPicker = document.getElementById("color-picker");
let isDrawing = false;
let currentPoint = {};
let lastPoint = {};
const strokePaths = [];
const undonestrokes = [];
// Set default brush info
const currentBrushInfo = {
style: "pencil",color: "#000000",width: 1,};
// information about the stroke currently being drawn
let currentstroke = {
points: [],brushInfo: {
style: null,color: null,width: null
},};
function distanceBetween(point1,point2) {
return Math.sqrt(
Math.pow(point2.x - point1.x,2) + Math.pow(point2.y - point1.y,2)
);
};
function angleBetween(point1,point2) {
return Math.atan2(point2.x - point1.x,point2.y - point1.y);
};
function getPointerPositionOnCanvas(pointerEvent) {
const rect = canvas.getBoundingClientRect();
const x = pointerEvent.pageX - rect.left - window.pageXOffset;
const y = pointerEvent.pageY - rect.top - window.pageYOffset;
return {
x,y
};
};
function drawCircle(context,x,y,radius) {
context.beginPath();
context.arc(x,radius,false,Math.PI * 2);
context.closePath();
context.fill();
};
function onPointerDown(e) {
isDrawing = true;
const {
x,y
} = getPointerPositionOnCanvas(e);
lastPoint = {
x,y
};
currentstroke.points = [];
currentstroke.brushInfo = currentBrushInfo;
drawCircle(ctx,currentBrushInfo.width);
addPointTostroke(x,y);
};
function onPointerMove(e) {
if (!isDrawing) return;
const {
x,y
} = getPointerPositionOnCanvas(e);
currentPoint = {
x,y
};
let dist = distanceBetween(lastPoint,currentPoint);
let angle = angleBetween(lastPoint,currentPoint);
let spacing = 2;
// Paints in between points to prevent gaps when drawing quickly
for (let i = 0; i < dist; i += spacing) {
let _x = lastPoint.x + Math.sin(angle) * i;
let _y = lastPoint.y + Math.cos(angle) * i;
drawCircle(ctx,_x,_y,currentBrushInfo.width);
addPointTostroke(_x,_y);
}
lastPoint = currentPoint;
};
function onPointerUp() {
isDrawing = false;
currentPoint = {};
strokePaths.push(currentstroke); // Records stroke in stroke history array
undonestrokes.length = 0;
currentstroke = {};
console.log(`stroke history:`);
console.log(strokePaths);
};
function setColor(e) {
let color = e.target.value;
ctx.fillStyle = color;
currentBrushInfo.color = color;
}
function addPointTostroke(x,y) {
const point = [x,y];
currentstroke.points.push(point);
}
function clearCanvas() {
ctx.clearRect(0,canvas.width,canvas.height);
}
// Redraws the canvas using strokePaths array
function redrawCanvas() {
if (strokePaths.length > 0) {
strokePaths.forEach((stroke) => {
let width = stroke.brushInfo.width;
let color = stroke.brushInfo.color;
ctx.fillStyle = color; // This *should* change the color for each stroke drawn
// Loops through all the points in the stroke and redraws each one using the brush settings recorded in the stroke object
stroke.points.forEach((point) => {
let x = point[0];
let y = point[1];
drawCircle(ctx,width);
});
});
}
}
// Removes most recent stroke from strokePaths,places into undonestrokes array,then redraws canvas using the updated history
function undostroke() {
if (strokePaths.length > 0) {
const undonestroke = strokePaths.pop();
undonestrokes.push(undonestroke);
clearCanvas();
redrawCanvas();
}
console.log(`Undone strokes:`);
console.log(undonestrokes);
}
function redostroke() {
if (undonestrokes.length > 0) {
const strokeToRedo = undonestrokes.pop();
strokePaths.push(strokeToRedo);
clearCanvas();
redrawCanvas();
} else return;
}
// Event listeners
canvas.addEventListener("pointerdown",onPointerDown);
canvas.addEventListener("pointermove",onPointerMove);
canvas.addEventListener("pointerup",onPointerUp);
colorPicker.addEventListener("change",setColor)
window.addEventListener("keydown",(e) => {
if (e.ctrlKey && e.code == "KeyZ") {
undostroke();
}
});
window.addEventListener("keydown",(e) => {
if (e.ctrlKey && e.code == "KeyY") {
redostroke();
}
});
每次笔画后,笔画历史数组都会记录到控制台,因此您可以实时看到颜色属性的变化。
我一直在绞尽脑汁,但不知道是什么原因造成的,或者我该如何解决。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。