如何使用鼠标移动在SVG上绘制一个矩形?

4

我在某人的 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
3个回答

10
为了完全模拟canvas方法的行为,使您能够通过在任何方向上单击和拖动来绘制矩形(即从右下到左上或反之),需要根据当前鼠标坐标相对于初始mousedown点的位置有条件地处理x、y、宽度和高度值。此外,下面的代码段包括一个函数,如果您正在对转换后的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;
}
<svg id="svg" width="800" height="500"></svg>


感谢@benvc的分享。 - Donnie Kerr

3

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>


1
我修改了Jason的回答,可以在代码中动态创建矩形元素。

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>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接