SVG 多边形缩放并相应地设置点

SVG polygon scale and set points accordingly

嗨 Stack overflowers :)

我正在努力处理一个 svg 多边形对象,我需要能够调整它的大小(按比例),save/set 新的点值。目前,我可以通过对 SVG 对象应用 CSS 变换来做到这一点,但这不会改变点属性值。这有可能吗?我的 SVG 多边形如下所示:

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

提前致谢:)

好吧,您可以通过偏移 (+/-) 像素值 expand/contract 多边形,这将改变其点值。所讨论的多边形必须是凸的。 此外,下面的示例可以缩放多边形,然后使用矩阵变换在缩放变换后重新计算其点。

试试下面的方法

<!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((a.x - c.x) * (b.y - a.y) - (a.x - b.x) * (c.y - a.y));
  total_area += area;
  centroid[0] += area * (a.x + b.x + c.x);
  centroid[1] += area * (a.y + b.y + c.y);
 }
 centroid[0] /= total_area * 3;
 centroid[1] /= total_area * 3;

 var points_offset = [];
 for (i = 0; i < m; i++)
 {
  //--- a-b 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 / ((b.y - a.y) / (b.x - a.x));

  //---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 (a.y == b.y)
   w = 0;
  else
      w = (a.y < b.y ? -1 : 1) * Math.sqrt(offset * offset / (1 + slope * slope));

  if (w == 0)
   h = (a.x > b.x ? -1 : 1) * offset;
  else
   h = slope * w;

  //---root svg element---
  var d=rootSVG.createSVGPoint()
  var e=rootSVG.createSVGPoint()
  d.x = a.x + w
  d.y = a.y + h

  if (slope == 0)
  {
   e.x = d.x
   e.y=d.y + 10
  }
  else
  {
   e.x = d.x + 10,
   e.y=d.y - 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([
  ((d.x * e.y - d.y * e.x) * (centroid[0] - a.x) - (d.x - e.x) * (centroid[0] * a.y - centroid[1] * a.x))
  / ((d.x - e.x) * (centroid[1] - a.y) - (d.y - e.y) * (centroid[0] - a.x)),
  ((d.x * e.y - d.y * e.x) * (centroid[1] - a.y) - (d.y - e.y) * (centroid[0] * a.y - centroid[1] * a.x))
  / ((d.x - e.x) * (centroid[1] - a.y) - (d.y - e.y) * (centroid[0] - a.x))
  ]);
 }
 return points_offset
}

 </script>
 </body>
</html>