Reputation: 7864
I found code on someone's fiddle to stroke on mouse move (click and move strokes). My requirement is to stroke rectangle on a SVG with mouse move in the same way. Is it possible, if yes, how?
//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
Upvotes: 4
Views: 5904
Reputation: 15130
In order to fully mimic the behavior of the canvas
approach that enables you to draw a rectangle by clicking and dragging in any direction (i.e. lower right to top left or vice versa), you need to conditionally handle the x, y, width, and height values based on the position of the current mouse coordinates relative to the point of the initial mousedown
. In addition, the snippet below includes a function that returns the correct coordinates if you are "drawing" on a transformed SVG element (or transformed child element).
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>
Upvotes: 10
Reputation: 7864
Tweaked Jason's answer to create rect element on the fly
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>
Upvotes: 1
Reputation: 37
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>
Upvotes: 3