微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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 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 举报,一经查实,本站将立刻删除。