【问题标题】:How to draw a rectangle on SVG with mouse move?如何通过鼠标移动在 SVG 上绘制矩形?
【发布时间】:2019-12-21 11:36:38
【问题描述】:

我在某人的fiddle 上找到了可以在鼠标移动时进行描边的代码(单击并移动描边)。我的要求是以相同的方式用鼠标移动在 SVG 上描边矩形。有没有可能,如果有,怎么做?

//Canvas
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
//Variables
let canvasx = canvas.offsetLeft;
let canvasy = canvas.offsetTop;
let last_mousex = 0;
let last_mousey = 0;
let mousex = 0;
let mousey = 0;
let mousedown = false;

//Mousedown
canvas.onmousedown = ({
  clientX,
  clientY
}) => {
  last_mousex = parseInt(clientX - canvasx);
  last_mousey = parseInt(clientY - canvasy);
  mousedown = true;
};

//Mouseup
canvas.onmouseup = () => mousedown = false;


//Mousemove

canvas.onmousemove = ({
  clientX,
  clientY
}) => {
  mousex = parseInt(clientX - canvasx);
  mousey = parseInt(clientY - canvasy);
  if (mousedown) {
    ctx.clearRect(0, 0, canvas.width, canvas.height); //clear canvas
    ctx.beginPath();
    const width = mousex - last_mousex;
    const height = mousey - last_mousey;
    ctx.rect(last_mousex, last_mousey, width, height);
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 10;
    ctx.stroke();
  }
};
canvas {
  cursor: crosshair;
  border: 1px solid #000000;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>

<body>

  <canvas id="canvas" width="800" height="500"></canvas>

</body>

</html>
Some Code// To prevent Stackoverflow error, please ignore

【问题讨论】:

    标签: javascript html css svg canvas


    【解决方案1】:

    const svg = document.querySelector('#svg');
    const rect = document.querySelector('#rect');
    
    let last_mousex = 0;
    let last_mousey = 0;
    let mousex = 0;
    let mousey = 0;
    let mousedown = false;
    
    //Mousedown
    svg.onmousedown = ({
      x,
      y
    }) => {
      last_mousex = x;
      last_mousey = y;
      mousedown = true;
    };
    
    //Mouseup
    svg.onmouseup = () => mousedown = false;
    
    //Mousemove
    svg.onmousemove = ({
      x,
      y
    }) => {
      mousex = parseInt(x);
      mousey = parseInt(y);
      if (mousedown) {
        const width = Math.abs(mousex - last_mousex);
        const height = Math.abs(mousey - last_mousey);
        rect.setAttribute('x', last_mousex);
        rect.setAttribute('y', last_mousey);
        rect.setAttribute('width', width);
        rect.setAttribute('height', height);
        rect.style.fill = "none";
        rect.style.stroke = "black";
        rect.style['stroke-width'] = 5;
        svg.innerHTML = "";
        svg.appendChild(rect);
      }
    };
    svg {
      cursor: crosshair;
      border: 1px solid #000000;
    }
    <svg id="svg" width="800" height="500">
      <rect id="rect"></rect>
    </svg>

    【讨论】:

      【解决方案2】:

      调整 Jason 的答案以动态创建 rect 元素

      const svg = document.querySelector('#svg');
      const svgNS = svg.namespaceURI;
      const rect = document.createElementNS(svgNS, 'rect');
      
      let last_mousex = 0;
      let last_mousey = 0;
      let mousex = 0;
      let mousey = 0;
      let mousedown = false;
      
      //Mousedown
      svg.onmousedown = ({
        x,
        y
      }) => {
        last_mousex = x;
        last_mousey = y;
        mousedown = true;
      };
      
      //Mouseup
      svg.onmouseup = () => mousedown = false;
      
      //Mousemove
      svg.onmousemove = ({
        x,
        y
      }) => {
        mousex = parseInt(x);
        mousey = parseInt(y);
        if (mousedown) {
          const width = Math.abs(mousex - last_mousex);
          const height = Math.abs(mousey - last_mousey);
          rect.setAttributeNS(null, 'x', last_mousex);
          rect.setAttributeNS(null, 'y', last_mousey);
          rect.setAttributeNS(null, 'width', width);
          rect.setAttributeNS(null, 'height', height);
          rect.setAttributeNS(null, 'fill', "none");
          rect.setAttributeNS(null, 'stroke', "black");
          rect.setAttributeNS(null, 'stroke-width', 5);
      
      
      
          // svg.innerHTML = "";
          svg.appendChild(rect);
        }
      };
      svg {
        cursor: crosshair;
        border: 1px solid #000000;
      }
      <svg id="svg" width="800" height="500">
      </svg>

      【讨论】:

        【解决方案3】:

        为了完全模仿canvas 方法的行为,该方法使您能够通过单击并沿任意方向拖动来绘制矩形(即右下角到左上角,反之亦然),您需要有条件地处理 x, y、宽度和高度值基于当前鼠标坐标相对于初始mousedown 的点的位置。此外,下面的 sn-p 包含一个函数,如果您在转换后的 SVG 元素(或转换后的子元素)上“绘图”,该函数会返回正确的坐标。

        const svg = document.querySelector('#svg');
        const svgPoint = (elem, x, y) => {
          const p = svg.createSVGPoint();
          p.x = x;
          p.y = y;
          return p.matrixTransform(elem.getScreenCTM().inverse());
        };
        
        svg.addEventListener('mousedown', (event) => {
          const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
          const start = svgPoint(svg, event.clientX, event.clientY);
          const drawRect = (e) => {
            const p = svgPoint(svg, e.clientX, e.clientY);
            const w = Math.abs(p.x - start.x);
            const h = Math.abs(p.y - start.y);
            if (p.x > start.x) {
              p.x = start.x;
            }
        
            if (p.y > start.y) {
              p.y = start.y;
            }
        
            rect.setAttributeNS(null, 'x', p.x);
            rect.setAttributeNS(null, 'y', p.y);
            rect.setAttributeNS(null, 'width', w);
            rect.setAttributeNS(null, 'height', h);
            svg.appendChild(rect);
          };
        
          const endDraw = (e) => {
            svg.removeEventListener('mousemove', drawRect);
            svg.removeEventListener('mouseup', endDraw);
          };
          
          svg.addEventListener('mousemove', drawRect);
          svg.addEventListener('mouseup', endDraw);
        });
        svg {
          cursor: crosshair;
          border: 1px solid #000000;
        }
        
        rect {
          fill: none;
          stroke: #000000;
          stroke-width: 10;
        }
        &lt;svg id="svg" width="800" height="500"&gt;&lt;/svg&gt;

        【讨论】:

        • 感谢@benvc 的分享
        猜你喜欢
        • 1970-01-01
        • 2013-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-01
        • 1970-01-01
        相关资源
        最近更新 更多