Canvas绘图 | 项目实战

386 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天

大家好,我是朝朝。

# 鼠标事件 | 项目实战 续上一篇的实战,这是另一个绘图需求,实现效果如图。

录制_2022_08_26_21_32_07_65.gif 这次主要是用接触canvas。 相当于,以canvas为画布,以code为画笔,设置画笔的颜色、笔的粗细、走势,重绘操作为橡皮擦。

说的这么好听,实际上只实现了一点简单的功能😏。

先入个门。

<canvas id="canvas"></canvas>
const canvas = document.getElementById('canvas'); // 获取元素
const ctx = canvas.getContext('2d'); // 获取画笔

ctx.fillStyle = 'green'; // 设置颜色
ctx.fillRect(10, 10, 150, 100); // 设置落笔点和矩形宽高

会涉及到画笔不流畅的问题

功能点

  1. 在画板上画直线,起点有删除按钮
  2. 每一条先都可以删除
  3. 限制只能删除n条线
  4. 按钮点击清空所有线条

解决方案

  1. 使用一个数组保存所有线段的起始&结束的坐标
  2. 解决1-画上每一条直线的时候给起点画上圆圈和叉叉
  3. 解决2-鼠标点击时判断位置是不是已有线段起点坐标的一定区域上。如果是,在数组上删除改线条,重新绘制数组表示的线条
  4. 解决3-在鼠标点击时判断数组有是否已经有n条线段
  5. 解决4-清空画布,数组置空

代码实现

  1. html部分
<body>
  <canvas width="800" height="800" style="border: 1px solid black;" id="canvas"></canvas>
  <button onclick="onClear()">清空</button>
</body>
  1. 样式部分
body {
  margin: 0;
  width: 100%;
  height: 1200px;
  border: 1px solid black;
}
  1. js部分
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let lines = []; // 保存已经在画图上的线条
/**
 * 删除线段
*/
function onClear() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  lines = [];
}

/**
 *  画小箭头和删除按钮 
*/
function drawArrow(point) {
  // 画线
  ctx.strokeStyle = 'black';
  ctx.beginPath();
  ctx.moveTo(point.startP.x, point.startP.y);
  ctx.lineTo(point.endP.x, point.endP.y);
  ctx.stroke();

  // 画圈
  ctx.beginPath();
  ctx.arc(point.startP.x, point.startP.y, 10, 0, 2*Math.PI);
  ctx.fillStyle = 'red';
  ctx.fill();

  // 画叉-1
  ctx.strokeStyle = 'white';
  ctx.beginPath();
  ctx.moveTo(point.startP.x-5, point.startP.y+5);
  ctx.lineTo(point.startP.x+5, point.startP.y-5);
  ctx.stroke();

  // 画叉-2
  ctx.beginPath();
  ctx.moveTo(point.startP.x+5, point.startP.y+5);
  ctx.lineTo(point.startP.x-5, point.startP.y-5);
  ctx.stroke();
}
  • 事件部分 image.png

鼠标按下:记录起点位置 / 触发删除 / 线条超过n条

document.body.addEventListener('mousedown', (e) => {
  let info = {
    startP: {
      x: e.pageX,
      y: e.pageY
    }
  }
  // 1、鼠标点击时,点在×上,删除该线
  let index = lines.findIndex(item => {
    const incline = Math.sqrt(Math.pow(info.startP.x - item.startP.x, 2) + Math.pow(info.startP.y - item.startP.y, 2));
    return incline < 10;
  });
  if (index >= 0) {
    lines.splice(index, 1);
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    lines.forEach(item => drawArrow(item));
    return;
  }

  if (info.startP.x > canvas.width || info.startP.y > canvas.height) {
    return;
  }
  // 2、图画上的线条小于等于4
  if (lines.length >= 4) {
    alert('最多只能画四条');
    return;
  }
  lines.push(info);
  
  document.body.addEventListener('mousemove',moveFun);
  document.body.addEventListener('mouseup', upFun);
})

鼠标移动:重绘 / 越界 / 画当前线条

function moveFun(e) {
  const {x, y} = lines[lines.length - 1].startP;
  // 重绘
  ctx.clearRect(0,0,canvas.width,canvas.height);
  for(let i=0; i<lines.length - 1; i++) {
    drawArrow(lines[i]);
  }
  // 越界了处理
  if (e.pageX <= 0 || e.pageX >= canvas.width || e.pageY <= 0 || e.pageY >= canvas.height) {
    lines[lines.length-1] = {
    ...lines[lines.length-1],
      endP: {
        x: e.pageX,
        y: e.pageY,
      }
    }
    ctx.clearRect(0,0,canvas.width,canvas.height);
    lines.forEach(item => {
      drawArrow(item);
    });
    document.body.removeEventListener('mousemove', moveFun);
    document.body.removeEventListener('mouseup', upFun);
    return;
  }
  ctx.strokeStyle = 'black';
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo( e.pageX, e.pageY);
  ctx.stroke();
}

鼠标松开:(记录松开的坐标 & 画所有的线段)/ 线段太短不画

function upFun(e) {
  lines[lines.length-1] = {
    ...lines[lines.length-1],
    endP: {
      x: e.pageX,
      y: e.pageY,
    }
  }
  // 如果移动距离小于关闭按钮的半径,就不会画
  const point = lines[lines.length-1];
  const incline = Math.sqrt(Math.pow(point.startP.x - point.endP.x, 2) + Math.pow(point.startP.y - point.endP.y, 2));
  if (incline <= 10) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    lines.pop();
    lines.forEach(item => {
      drawArrow(item);
    })
  } else {
    drawArrow(lines[lines.length-1]);
  }

  document.body.removeEventListener('mousemove', moveFun);
  document.body.removeEventListener('mouseup', upFun);
}

参考:# Canvas

那么,next hui see