简体   繁体   中英

SVG polygon scale and set points accordingly

Hi Stack overflowers :)

I'm struggling with a svg polygon object which I need to be able to resize (proportionally), and save/set the new points values. At the moment I can do this by applying CSS transform to the SVG object, but that doesn't change the points attribute values. Is this possible somehow? My SVG polygon looks like this:

 <svg viewBox="0 0 100 100" style="width: 100px; height: 100px;"> <polygon fill="black" points="0,0 50,0 100,100 0,100" /> </svg> 

Thanks in advance :)

Well, you can expand/contract a polygon via an offset(+/-) pixel value, and that will change its points values. The polygon in question must be convex. Also, the example below can scale the polygon and then recompute its points following the scale transform, using matrix transforms.

Give the following a try

 <!DOCTYPE HTML> <html> <head> <title>Resize Convex Polygon</title> </head> <body> <center> Offset(+/-)&nbsp;px.<input type="text" style="width:50px" id=offsetValue value=10 /><button onClick=resizeMyPolygon()>Resize Polygon</button> <br> <button onClick=scalePolygon() >Scale Polygon</button> <br> <svg xmlns="http://www.w3.org/2000/svg" id="mySVG" width="600" height="600"> <polygon id="myPolygon" fill="yellow" stroke="black" stroke-width="1" points="380,80 200,10 40,80 100,320 300,350"></polygon> <svg> </center> <script> //---button--- function scalePolygon() { //---scale from center of polygon-- var bb=myPolygon.getBBox() var bbx=bb.x var bby=bb.y var bbw=bb.width var bbh=bb.height var cx=bbx+.5*bbw var cy=bby+.5*bbh myPolygon.setAttribute("transform","translate("+cx+" "+cy+")scale(1.2)translate("+(-cx)+" "+(-cy)+")") screenPolygon(myPolygon) console.log(myPolygon.getAttribute("points")) } function screenPolygon(myPoly) { var sCTM = myPoly.getCTM() var svgRoot = myPoly.ownerSVGElement var pointsList = myPoly.points; var n = pointsList.numberOfItems; for(var m=0; m < n; m++) { var mySVGPoint = svgRoot.createSVGPoint(); mySVGPoint.x = pointsList.getItem(m).x mySVGPoint.y = pointsList.getItem(m).y mySVGPointTrans = mySVGPoint.matrixTransform(sCTM) pointsList.getItem(m).x=mySVGPointTrans.x pointsList.getItem(m).y=mySVGPointTrans.y }; //---force removal of transform-- myPoly.setAttribute("transform","") myPoly.removeAttribute("transform") } //---button--- function resizeMyPolygon() { var pointList=myPolygon.points //---clockwise or counterclockwise-- function polygonArea() { var area = 0; for (var i = 0; i < pointList.length; i++) { j = (i + 1) % pointList.length; area += pointList.getItem(i).x * pointList.getItem(j).y; area -= pointList.getItem(j).x * pointList.getItem(i).y; } return area / 2; } var clockwise = polygonArea() > 0; //---false is ccw points-- var offset=parseFloat(offsetValue.value) if((offset>0&& clockwise==true)||(offset<0&&clockwise==false)) { //--reverse polygon points--- var pointArray=[] for(var k=pointList.numberOfItems-1;k>=0;k--) { var lastPnt=pointList.getItem(k) pointArray.push([lastPnt.x,lastPnt.y]) } myPolygon.setAttribute("points",pointArray.join() ) pointList=myPolygon.points } var changedPoints=resizePolygon(pointList,offset,mySVG) myPolygon.setAttribute("points",changedPoints.join() ) console.log(myPolygon.getAttribute("points")) } function resizePolygon(pointsList,offset,rootSVG) { var m=pointsList.numberOfItems //---first find centroid--- var total_area = 0; var centroid = [0, 0]; var a = pointsList.getItem(0); for (i = 0; i < m - 2; i++) { var b = pointsList.getItem(i + 1) var c = pointsList.getItem(i + 2); var area = 0.5 * Math.abs((ax - cx) * (by - ay) - (ax - bx) * (cy - ay)); total_area += area; centroid[0] += area * (ax + bx + cx); centroid[1] += area * (ay + by + cy); } centroid[0] /= total_area * 3; centroid[1] /= total_area * 3; var points_offset = []; for (i = 0; i < m; i++) { //--- ab is a line segment on the convex polygon--- var a = pointsList.getItem(i); var b = pointsList.getItem(i == m - 1 ? 0 : i + 1); //---Determine the normal to the line segment--- var slope = -1 / ((by - ay) / (bx - ax)); //---Construct a new line d--e that is the line a--b shifted 'offset'--- //---units in the direction of the normal--- var w, h; if (ay == by) w = 0; else w = (ay < by ? -1 : 1) * Math.sqrt(offset * offset / (1 + slope * slope)); if (w == 0) h = (ax > bx ? -1 : 1) * offset; else h = slope * w; //---root svg element--- var d=rootSVG.createSVGPoint() var e=rootSVG.createSVGPoint() dx = ax + w dy = ay + h if (slope == 0) { ex = dx ey=dy + 10 } else { ex = dx + 10, ey=dy - 10 / slope } //---Intersect the line d--e with centroid--a, which is the point on--- //---the inflated convex polygon--- //---http://en.wikipedia.org/wiki/Line-line_intersection--- points_offset.push([ ((dx * ey - dy * ex) * (centroid[0] - ax) - (dx - ex) * (centroid[0] * ay - centroid[1] * ax)) / ((dx - ex) * (centroid[1] - ay) - (dy - ey) * (centroid[0] - ax)), ((dx * ey - dy * ex) * (centroid[1] - ay) - (dy - ey) * (centroid[0] * ay - centroid[1] * ax)) / ((dx - ex) * (centroid[1] - ay) - (dy - ey) * (centroid[0] - ax)) ]); } return points_offset } </script> </body> </html> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM