Mission requirements

Click the mouse, and a border appears on the path. Rotate the path with the mouse. (You can’t just use transform because the coordinates of all points need to be recorded at the end.)

The basic idea

  • Find the coordinates of the rotation center of path (x,y)
  • Gets the Angle of mouse movement with respect to the rotation center
  • Rotate path via TansForm (without changing coordinates in pathList)
  • When the mouse is released, record the current Angle and then make a matrix change to the current path (change the coordinates in the pathList).

Preliminary knowledge

  • How to calculate the rotation center of path?
Using getBBox () to get the element boundary, returns an object {x, y, width, height}, center of rotation is the center of the matrix (diagonal cross center) let SVG = document. The getElementsByTagName (' SVG) [0]; // Let path1 = document.getelementById ('path'); Let svgBox = path1.getBbox (); Boundaries will return an object / / x y width height let the rect = document. The createElementNS (" http://www.w3.org/2000/svg ", "the rect"); SetAttribute ('x', svgbox.x); // Create a rect. rect.setAttribute('y',svgBox.y); rect.setAttribute('width',svgBox.width); rect.setAttribute('height',svgBox.height); rect.setAttribute('style','fill:none; stroke:pink; stroke-width:3; stroke-dasharray:5'); AppendChild (rect); // Add SVG to the page. // Let x = svgbox. x + (svgbox. width >> 1); let y = svgBox.y + (svgBox.height >> 1); cirx = x; ciry = y; let point = document.createElementNS("http://www.w3.org/2000/svg","circle"); point.setAttribute('cx',x); point.setAttribute('cy',y); point.setAttribute('r',2); point.setAttribute('style','fill:pink'); svg.appendChild(point);Copy the code

  • Calculate the Angle of mouse movement?
Const getAngle = ({x: x1, y: y1}, {x: x2, y: y) const getAngle = ({x: x1, y: y1}, {x: x2, y: y) y2 }) => { const dot = x1 * x2 + y1 * y2 const det = x1 * y2 - y1 * x2 const angle = Math.atan2(det, dot) / Math.PI * 180 return (angle + 360) % 360 } let angle = getAngle({ x: prex - cirx, y: prey - ciry, }, { x: nowx - cirx, y: nowy - ciry, });Copy the code
  • Get the coordinates of the transform changed
Let CTM = path1.getScreenctm (); let CTM = path1.getScreenctm (); var rootCTM = svg.getScreenCTM(); var pt1 = svg.createSVGPoint(); pt1.x = 100; pt1.y = 100; // Let pt2 = pt1.matrixTransform(roottm.inverse ().multiply(CTM));Copy the code
methods2:let  l = ((angle * Math.PI) / 180);
        	let  cosv =  Math.cos(l);
	   	let  sinv =  Math.sin(l);
        	let pt3 = {x: -1.y: -1};
		pt3.x = ((pt1.x - cirx) * cosv - (pt1.y - ciry) * sinv + cirx);
		pt3.y =  ((pt1.x - cirx) * sinv + (pt1.y - ciry) * cosv + ciry);
        	console.log("Manual calculation"+pt3.x+""+pt3.y);
Copy the code

Some little potholes

Rotate on both the border and the path. When the mouse is loose, calculate the real coordinates of the path and set the rotate to 0. If the boundary is the same as the boundary obtained by getBBox(), rotate on the border and the path. The edge is restored to where it was without rotation (because rotate is 0).

So instead of using rect to represent the boundary, use the path of a child custom D to represent the boundary, calculating the new coordinates of the rotated boundary when the mouse is released, so that the border stays normal until the next path is clicked.

The current version also has a Bug where the border does not change when the strokeWidth of the path changes, so some parts of the path may be outside the border. This problem is solved after thinking of a good way…