【问题标题】:Normalize a SVG for easy storage标准化 SVG 以便于存储
【发布时间】:2014-01-22 23:18:20
【问题描述】:

我有一个要存储在数据库中的 SVG 文件。将所有对象存储为多边形并存储坐标会非常有帮助。但是,我使用的文件是从 Ilustrator 导出的。它确实包含多边形,但也包含变换的矩形和其他形式。元素不必以绝对精度呈现,因此舍入误差不是问题。

如何转换转换后的矩形?

没关系:

<polygon points="2694.423,2972.209 2685.76,2982.961 2702.282,2996.274
2710.938,2985.526   "/

并且可以存储为坐标列表。 这是有问题的

<rect x="4316.474" y="2236.01" transform="matrix(-0.3208 -0.9471 0.9471 -0.3208 3591.1353 7063.0771)" width="22.991" height="15.92"/>

并且应该像第一个示例一样转换为多边形。

最终我想使用 html5 画布来显示形状。

为了渲染多边形数据,我使用了 kinecticjs 框架,方法如下:

    function poly (layer, points)
{
    var poly = new Kinetic.Line({
        points: points,
        fill: 'black',
        stroke: 'black',
        strokeWidth: 0,
        closed: true
      });
  // add the shape to the layer
  layer.add(poly);
  return poly;
}

canvas 与 svg 是否存在性能问题?我有大约 3000 个可点击对象要渲染。

【问题讨论】:

    标签: javascript html canvas svg adobe-illustrator


    【解决方案1】:

    关于问题:

    canvas 与 svg 是否存在性能问题?我有大约 3000 个可点击对象进行渲染。

    3000 个元素没问题。但是您不能在单个画布元素上包含事件。

    【讨论】:

    • 是否可以包含一个事件处理程序,我可以使用它来定位单击的多边形?还是建议使用带有可点击地图的 SVG?
    • 我建议使用 svg 而不是画布。访问事件的每个元素要容易得多,otc。我认为使用画布没有性能优势。
    【解决方案2】:

    可以使用http://petercollingridge.appspot.com/svg_optimiser 实现应用转换规范化步骤。

    至于第二步,您可能需要为此添加自己的代码。

    【讨论】:

      【解决方案3】:

      在许多情况下,将某些 svg 元素(直线、矩形、圆、椭圆、多边形、折线和路径)在转换后返回到它们的屏幕 x,y 值是有意义的。这是使用 getCTMma​​trixTransform 完成的 注意:对带有笔划的元素使用 vector-effect="non-scaling-stroke"(*在 IE 中不可用)。 以下是为各种转换后的 svg 元素返回屏幕点的代码:

      //----build a generic document SVG root to hold svg point---
      function screenLine(line,svg)
      {
          var sCTM = line.getCTM()
          var x1=parseFloat(line.getAttribute("x1"))
          var y1=parseFloat(line.getAttribute("y1"))
          var x2=parseFloat(line.getAttribute("x2"))
          var y2=parseFloat(line.getAttribute("y2"))
      
          var mySVGPoint1 = svg.createSVGPoint();
          mySVGPoint1.x = x1
          mySVGPoint1.y = y1
          mySVGPointTrans1 = mySVGPoint1.matrixTransform(sCTM)
          line.setAttribute("x1",mySVGPointTrans1.x)
          line.setAttribute("y1",mySVGPointTrans1.y)
      
          var mySVGPoint2 = svg.createSVGPoint();
          mySVGPoint2.x = x2
          mySVGPoint2.y = y2
          mySVGPointTrans2= mySVGPoint2.matrixTransform(sCTM)
          line.setAttribute("x2",mySVGPointTrans2.x)
          line.setAttribute("y2",mySVGPointTrans2.y)
          //---force removal of transform--
          line.setAttribute("transform","")
          line.removeAttribute("transform")
      }
      function screenCircle(circle,svg)
      {
          var sCTM = circle.getCTM()
          var scaleX  = sCTM.a;
      
          var cx=parseFloat(circle.getAttribute("cx"))
          var cy=parseFloat(circle.getAttribute("cy"))
      
          var r=parseFloat(circle.getAttribute("r"))
      
          var mySVGPointC = svg.createSVGPoint();
          mySVGPointC.x = cx
          mySVGPointC.y = cy
          mySVGPointTransC = mySVGPointC.matrixTransform(sCTM)
          circle.setAttribute("cx",mySVGPointTransC.x)
          circle.setAttribute("cy",mySVGPointTransC.y)
      
          circle.setAttribute("r",r*scaleX)
          //---force removal of transform--
          circle.setAttribute("transform","")
          circle.removeAttribute("transform")
      }
      function screenEllipse(ellipse,svg)
      {
          var sCTM = ellipse.getCTM()
          var scaleX  = sCTM.a;
          var scaleY  = sCTM.d;
      
          var cx=parseFloat(ellipse.getAttribute("cx"))
          var cy=parseFloat(ellipse.getAttribute("cy"))
      
          var rx=parseFloat(ellipse.getAttribute("rx"))
          var ry=parseFloat(ellipse.getAttribute("ry"))
      
          var mySVGPointC = svg.createSVGPoint();
          mySVGPointC.x = cx
          mySVGPointC.y = cy
          mySVGPointTransC = mySVGPointC.matrixTransform(sCTM)
          ellipse.setAttribute("cx",mySVGPointTransC.x)
          ellipse.setAttribute("cy",mySVGPointTransC.y)
      
          ellipse.setAttribute("rx",rx*scaleX)
          ellipse.setAttribute("ry",ry*scaleY)
      
          //---force removal of transform--
          ellipse.setAttribute("transform","")
          ellipse.removeAttribute("transform")
      }
      function screenRect(rect,svg)
      {
          var sCTM = rect.getCTM()
          var scaleX  = sCTM.a;
          var scaleY  = sCTM.d;
      
          var x=parseFloat(rect.getAttribute("x"))
          var y=parseFloat(rect.getAttribute("y"))
      
          var width=parseFloat(rect.getAttribute("width"))
          var height=parseFloat(rect.getAttribute("height"))
      
          var mySVGPoint = svg.createSVGPoint();
          mySVGPoint.x = x
          mySVGPoint.y = y
          mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
          rect.setAttribute("x",mySVGPointTrans.x)
          rect.setAttribute("y",mySVGPointTrans.y)
      
          rect.setAttribute("width",width*scaleX)
          rect.setAttribute("height",height*scaleY)
      
          //---force removal of transform--
          rect.setAttribute("transform","")
          rect.removeAttribute("transform")
      }
      function screenPolyline(myPoly,svg)
      {
          var sCTM = myPoly.getCTM()
          var pointsList = myPoly.points;
          var n = pointsList.numberOfItems;
          for(var m=0;m<n;m++)
          {
              var mySVGPoint = mySVG.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")
      }
      
      function screenPath(path,svg)
      {
          var sCTM = path.getCTM()
          var scaleX  = sCTM.a;
          var scaleY  = sCTM.d;
      
          var segList=path.pathSegList
          var segs=segList.numberOfItems
          //---change segObj values
          for(var k=0;k<segs;k++)
          {
              var segObj=segList.getItem(k)
      
              if(segObj.x && segObj.y )
              {
                  var mySVGPoint = svg.createSVGPoint();
                  mySVGPoint.x = segObj.x
                  mySVGPoint.y = segObj.y
                  mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
                  segObj.x=mySVGPointTrans.x
                  segObj.y=mySVGPointTrans.y
              }
      
              if(segObj.x1 && segObj.y1)
              {
                  var mySVGPoint1 = svg.createSVGPoint();
                  mySVGPoint1.x = segObj.x1
                  mySVGPoint1.y = segObj.y1
                  mySVGPointTrans1 = mySVGPoint1.matrixTransform(sCTM)
                  segObj.x1=mySVGPointTrans1.x
                  segObj.y1=mySVGPointTrans1.y
              }
              if(segObj.x2 && segObj.y2)
              {
                  var mySVGPoint2 = svg.createSVGPoint();
                  mySVGPoint2.x = segObj.x2
                  mySVGPoint2.y = segObj.y2
                  mySVGPointTrans2 = mySVGPoint2.matrixTransform(sCTM)
                  segObj.x2=mySVGPointTrans2.x
                  segObj.y2=mySVGPointTrans2.y
              }
      
              if(segObj.r1)segObj.r1=segObj.r1*scaleX
              if(segObj.r2)segObj.r2=segObj.r2*scaleX
          }
          //---force removal of transform--
          path.setAttribute("transform","")
          path.removeAttribute("transform")
      }
      
      //---changes all transformed points to screen points---
      function screenPolygon(myPoly,mySVG)
      {
          var sCTM = myPoly.getCTM()
          var pointsList = myPoly.points;
          var n = pointsList.numberOfItems;
          for(var m=0;m<n;m++)
          {
              var mySVGPoint = mySVG.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")
      }
      

      【讨论】:

        【解决方案4】:

        鉴于:

        • 您未转换的 SVG 点

        • 还有你的 SVG 转换矩阵

        您可以在数学上将变换应用于这些点。

        结果点是转换后的 XY——“标准化”XY。

        生成的点将在与转换后的 SVG 点相同的位置绘制到画布上。

        生成的点不需要在正确的位置绘制 SVG 转换。

        下面是应用变换矩阵来“标准化”一个点的代码:

        function simplifyTransform(point,matrix){
            simpleX = point.x * matrix[0] + point.y * matrix[2] + matrix[4];
            simpleY = point.x * matrix[1] + point.y * matrix[3] + matrix[5];
            return({x:simpleX,y:simpleY});
        }
        

        这是一个插图:

        这是代码和演示:http://jsfiddle.net/m1erickson/ushWr/

        <!doctype html>
        <html>
        <head>
        <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
        <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
        
        <style>
            body{ background-color: ivory; }
            #canvas{border:1px solid red;}
        </style>
        
        <script>
        $(function(){
        
            var canvas=document.getElementById("canvas");
            var ctx=canvas.getContext("2d");
        
            var x=50;
            var y=50;
            var h=30;
            var w=50;
            var matrix=[1.25,.75,.75,1.25,20,20];
        
            ctx.save();
            ctx.transform(matrix[0],matrix[1],matrix[2],matrix[3],matrix[4],matrix[5],matrix[6]);
            ctx.fillStyle="red";
            ctx.fillRect(x,y,w,h);
            ctx.restore();
        
        
            // make an array of the 4 corners of the rectangle
            var points=[];
            points.push({x:x,y:y});
            points.push({x:x+w,y:y});
            points.push({x:x+w,y:y+h});
            points.push({x:x,y:y+h});
        
            // get the transformed rectangle's corners in untransformed space
            var rect=simplifyPoly(points,matrix);
        
            // stroke the untransformed rectangle
            ctx.save();
            ctx.strokeStyle="green";
            ctx.lineWidth=2;
            ctx.moveTo(rect[0].x,rect[0].y);
            for(var i=1;i<rect.length;i++){
                ctx.lineTo(rect[i].x,rect[i].y);
            }
            ctx.closePath();
            ctx.stroke();
            ctx.restore();
        
            function simplifyTransform(point,matrix){
                simpleX = point.x * matrix[0] + point.y * matrix[2] + matrix[4];
                simpleY = point.x * matrix[1] + point.y * matrix[3] + matrix[5];
                return({x:simpleX,y:simpleY});
            }
        
            function simplifyPoly(points,matrix){
                var simplePoints=[];
                for(var i=0;i<points.length;i++){
                    simplePoints.push(simplifyTransform(points[i],matrix));
                }
                return(simplePoints);
            }
        
        }); // end $(function(){});
        </script>
        
        </head>
        
        <body>
            <h4>The red fill is drawn using untransformed points plus a transform<br>The green stroke is drawn using the "simplified" points--no transform involved.</h4>
            <canvas id="canvas" width=300 height=300></canvas>
        </body>
        </html>
        

        【讨论】:

          【解决方案5】:

          经过更详细的搜索后,我发现 Peter Collingridge 在 http://petercollingridge.appspot.com/svg-editor/ 上进行了实验

          在 Illustrator 中,可以使用 Object/Path/Simplify 更改多边形中的变换矩形

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-08-03
            • 2015-05-18
            • 1970-01-01
            • 2011-02-10
            • 2013-05-31
            • 2018-09-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多