I am using react with typescript. I am working on SVG's but I am facing an issue with it. I am able to draw shapes inside SVGs but I am facing a problem while resizing it.
I want to make my shapes resizable like if the user selects the right size or edge and drags the shape with a mouse then the shape will resize accordingly to cursor position.
I searched a lot on the Internet to find, How to know on which position the user clicked on SVG.
here is my code:
const divRef = useRef<HTMLDivElement>(null);
const svgRef = useRef<SVGSVGElement>(null);
useEffect(() => {
const containerSvg = svgRef.current;
let p: DOMPoint;
let w: number;
let h: number;
if (containerSvg) {
const svgPoint = (elem: any, x: number, y: number) => {
const point = containerSvg.createSVGPoint();
point.x = x;
point.y = y;
return point.matrixTransform(elem.getScreenCTM().inverse());
};
containerSvg.addEventListener("mousedown", (event) => {
const rect = document.createElementNS(
"http://www.w3.org/2000/svg",
"rect"
);
const start = svgPoint(containerSvg, event.clientX, event.clientY);
const drawRect = (e: any) => {
p = svgPoint(containerSvg, e.clientX, e.clientY);
w = Math.abs(p.x - start.x);
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 as unknown) as string);
rect.setAttributeNS(null, "y", (p.y as unknown) as string);
rect.setAttributeNS(null, "width", (w as unknown) as string);
rect.setAttributeNS(null, "height", (h as unknown) as string);
containerSvg.appendChild(rect);
};
const endDraw = (e: any) => {
containerSvg.removeEventListener("mousemove", drawRect);
containerSvg.removeEventListener("mouseup", endDraw);
let offset: any;
let selectedRect: SVGRectElement | null;
rect.addEventListener("mousedown", startDrag);
rect.addEventListener("mousemove", drag);
rect.addEventListener("mouseup", endDrag);
rect.addEventListener("mouseleave", endDrag);
function startDrag(evt: any) {
evt.stopPropagation();
selectedRect = rect;
containerSvg?.classList.add("dragging");
selectedRect?.classList.add("target");
if (selectedRect) {
offset = getMousePosition(evt);
if (offset) {
let rectX = selectedRect.getAttributeNS(null, "x");
let rectY = selectedRect.getAttributeNS(null, "y");
if (rectX && rectY) {
offset.x -= parseFloat(rectX);
offset.y -= parseFloat(rectY);
}
}
}
}
function drag(evt: any) {
if (selectedRect) {
var coord = getMousePosition(evt);
if (coord && offset) {
let x = coord.x - offset.x;
let y = coord.y - offset.y;
if (x && y) {
selectedRect.setAttributeNS(
null,
"x",
(x as unknown) as string
);
selectedRect.setAttributeNS(
null,
"y",
(y as unknown) as string
);
}
}
}
}
function endDrag() {
containerSvg?.classList.remove("dragging");
selectedRect?.classList.remove("target");
selectedRect = null;
}
function getMousePosition(evt: any) {
var CTM = rect.getScreenCTM();
if (CTM) {
return {
x: (evt.clientX - CTM.e) / CTM.a,
y: (evt.clientY - CTM.f) / CTM.d
};
}
}
};
containerSvg.addEventListener("mousemove", drawRect);
containerSvg.addEventListener("mouseup", endDraw);
});
}
}, []);
return (
<div className=" App container" ref={divRef}>
<svg id="svg" ref={svgRef}></svg>
</div>
);