Canvas画布实现套索的效果

这篇博客介绍了如何利用JavaScript和canvas元素创建交互式的选取功能。通过监听鼠标事件,实现鼠标按下、移动和抬起时的绘制操作,绘制平滑的曲线,并在松开鼠标时清除画布。文章详细讲解了相关代码实现,包括创建canvas、设置样式、处理鼠标事件以及绘制贝塞尔曲线等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

好久没写博客了QUQ 记得上次写博客还是上次

<script>
  let isActive = false; //是否弃用
  let divContainer = document.getElementById("divContainer"); //生成的父级容器
  let drawingCanvas; //绘制的canvas
  let drawingContext; //绘制的canvas2d
  let isDrawing = false; //是否正在拖动
  let drewPoints = []; //画线的点

  function activate() {
    console.log(123)
    if (!isActive) {
      isActive = true;
      if (!document.getElementById("lasso")) {
        // 创建lasso的画布
        initDOM('canvas', 'lasso');
        drawingContext = drawingCanvas.getContext('2d');
        drawingCanvas.style.cursor = 'cursor';
      }
    }

    // 监听鼠标点击事件
    drawingCanvas.addEventListener("mousedown", (e) => {
      onDrawingStart(e)
    })
    // 监听鼠标移动事件
    drawingCanvas.addEventListener("mousemove", (e) => {
      onDrawing(e)
    })
    // 监听鼠标抬起事件
    drawingCanvas.addEventListener("mouseup", (e) => {
      onDrawingEnd(e)
    })
  }

  function initDOM(tag, id) {
    // 创建dom对象
    let dom = document.createElement(tag);
    // 添加style
    dom.style.position = 'absolute';
    dom.style.left = "0px";
    dom.style.top = "0px";
    dom.id = id;
    dom.style.backgroundColor = "rgba(245,245,245,1.0)"
    let width = "1000";
    let height = "500";

    // 设置宽高
    if (window.devicePixelRatio) {
      dom.style.width = width + "px";
      dom.style.height = height + "px";
      dom.height = height * window.devicePixelRatio;
      dom.width = width * window.devicePixelRatio;
    }
    divContainer.appendChild(dom);

    drawingCanvas = dom;
  }
  /**
  * 鼠标点击
  * @param event
  */
  function onDrawingStart(event) {
    let drawingRectangle = drawingCanvas.getBoundingClientRect();
    // 开始绘制
    if (isActive) {
      isDrawing = true;
      drewPoints = [];
      selectedNodes = [];

      drewPoints.push({
        x: event.clientX - drawingRectangle.left,
        y: event.clientY - drawingRectangle.top
      });
      // 改变鼠标形状
      drawingCanvas.style.cursor = 'cell';
      // 阻止默认事件发生
      event.stopPropagation();
    }
  }
  /**
  * 鼠标拖动
  * @param event
  */
  function onDrawing(event) {
    // 绘制线
    if (isActive && isDrawing) {
      let x = 0,
        y = 0,
        drawingRectangle = drawingCanvas.getBoundingClientRect();

      x = event.clientX;
      y = event.clientY;

      drewPoints.push({
        x: x - drawingRectangle.left,
        y: y - drawingRectangle.top
      });
      // 生成绘制的属性
      drawingContext.lineWidth = 2;
      drawingContext.strokeStyle = 'rgba(57,207,255,1.0)';
      drawingContext.fillStyle = 'rgba(224, 245, 255, 0.25)';
      drawingContext.lineJoin = 'round';
      drawingContext.lineCap = 'round';
      // 清空画布
      drawingContext.clearRect(0, 0, drawingContext.canvas.width, drawingContext.canvas.height);

      let sourcePoint = drewPoints[0],
        destinationPoint = drewPoints[1],
        pointsLength = drewPoints.length,
        // 获取绘制的曲线的控制点
        getMiddlePointCoordinates = function (firstPoint, secondPoint) {
          return {
            x: firstPoint.x + (secondPoint.x - firstPoint.x) / 2,
            y: firstPoint.y + (secondPoint.y - firstPoint.y) / 2
          };
        };
      // 开始绘制
      drawingContext.beginPath();
      drawingContext.moveTo(sourcePoint.x, sourcePoint.y);

      for (let i = 1; i < pointsLength; i++) {
        let middlePoint = getMiddlePointCoordinates(sourcePoint, destinationPoint);
        // 绘制贝赛尔曲线
        drawingContext.quadraticCurveTo(sourcePoint.x, sourcePoint.y, middlePoint.x, middlePoint.y);
        sourcePoint = drewPoints[i];
        destinationPoint = drewPoints[i + 1];
      }

      drawingContext.lineTo(sourcePoint.x, sourcePoint.y);
      drawingContext.stroke();
      // 填充
      drawingContext.fill();
      // 阻止默认事件发生
      event.stopPropagation();
    }
  }
  /**
  * 鼠标松开
  * @param e
  */
  function onDrawingEnd(e) {
    if (isActive && isDrawing) {
      isDrawing = false;
      drawingContext.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height);
      drawingCanvas.style.cursor = 'default';
      e.stopPropagation();
    }
  }

  activate()

</script>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值