【问题标题】:drawing centered arcs in raphael js在 raphael js 中绘制居中的弧线
【发布时间】:2011-02-21 00:55:55
【问题描述】:

我需要使用 raphael.js 绘制各种尺寸的同心圆弧。我试图理解http://raphaeljs.com/polar-clock.html背后的代码,这与我想要的非常相似,但是没有cmets,很难理解。

理想情况下,我需要一个函数来创建一条距离某个中心点给定距离、以某个角度开始并以某个角度结束的路径。

【问题讨论】:

    标签: raphael vector-graphics bezier geometric-arc


    【解决方案1】:

    这个答案是可以的,但不能动画。我为你从极地钟里撕下了重要的东西。这是一个红色的弧线,动画生长。享受。

    // Custom Arc Attribute, position x&y, value portion of total, total value, Radius
    var archtype = Raphael("canvas", 200, 100);
    archtype.customAttributes.arc = function (xloc, yloc, value, total, R) {
        var alpha = 360 / total * value,
            a = (90 - alpha) * Math.PI / 180,
            x = xloc + R * Math.cos(a),
            y = yloc - R * Math.sin(a),
            path;
        if (total == value) {
            path = [
                ["M", xloc, yloc - R],
                ["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R]
            ];
        } else {
            path = [
                ["M", xloc, yloc - R],
                ["A", R, R, 0, +(alpha > 180), 1, x, y]
            ];
        }
        return {
            path: path
        };
    };
    
    //make an arc at 50,50 with a radius of 30 that grows from 0 to 40 of 100 with a bounce
    var my_arc = archtype.path().attr({
        "stroke": "#f00",
        "stroke-width": 14,
        arc: [50, 50, 0, 100, 30]
    });
    
    my_arc.animate({
        arc: [50, 50, 40, 100, 30]
    }, 1500, "bounce");
    

    【讨论】:

    • 为方便起见,这是一个 jsfiddle 的答案,您可以在其中输入要绘制的圆圈的大小:jsfiddle.net/Bzdnm/2
    • 与此示例和 Polar Clock 示例一样,是否有人知道如何修改它以使起点不总是在 12 0'clock?我猜想 100 中的起始值会这样做,但它似乎不起作用。
    • 使用旋转方法。 CODE{ my_arc.rotate(-90, 50, 50).animate({ arc: [50, 50, amount, 100, 30] }, 1500, "bounce"); } 您可以在 Raphael 文档中找到更多信息。
    • 是否可以为弧指定与顶部不同的起点?
    • @Francisc - 如果您查看上面两行的评论,您会发现 daxiang28 提出了完全相同的问题。更有趣的是,如果您查看以下行,即问题上方的行,距离不超过 1 厘米,您可以找到您提出的问题的答案。
    【解决方案2】:

    这就是我的做法。以下代码允许您指定开始和结束角度以及内半径和外半径(对于制作那些流行的圆环式饼图很有用)。该解决方案不依赖于用线段近似曲线,并且可以按照原始问题中提到的时钟示例进行动画处理。

    首先创建你的 Raphael 绘图区;以下假设您的 HTML 文件中有一个 id 为“raphael_paper”的 div:

    var paper = Raphael("raphael_paper", 800, 800);
    

    我们为这个 Raphael 对象添加了一个自定义的arc 属性,一个接受圆心(x 和 y 坐标)、起始角度、结束角度、内半径和外半径的函数:

    paper.customAttributes.arc = function (centerX, centerY, startAngle, endAngle, innerR, outerR) {
        var radians = Math.PI / 180,
            largeArc = +(endAngle - startAngle > 180);
            // calculate the start and end points for both inner and outer edges of the arc segment
            // the -90s are about starting the angle measurement from the top get rid of these if this doesn't suit your needs
            outerX1 = centerX + outerR * Math.cos((startAngle-90) * radians),
            outerY1 = centerY + outerR * Math.sin((startAngle-90) * radians),
            outerX2 = centerX + outerR * Math.cos((endAngle-90) * radians),
            outerY2 = centerY + outerR * Math.sin((endAngle-90) * radians),
            innerX1 = centerX + innerR * Math.cos((endAngle-90) * radians),
            innerY1 = centerY + innerR * Math.sin((endAngle-90) * radians),
            innerX2 = centerX + innerR * Math.cos((startAngle-90) * radians),
            innerY2 = centerY + innerR * Math.sin((startAngle-90) * radians);
    
        // build the path array
        var path = [
            ["M", outerX1, outerY1], //move to the start point
            ["A", outerR, outerR, 0, largeArc, 1, outerX2, outerY2], //draw the outer edge of the arc
            ["L", innerX1, innerY1], //draw a line inwards to the start of the inner edge of the arc
            ["A", innerR, innerR, 0, largeArc, 0, innerX2, innerY2], //draw the inner arc
            ["z"] //close the path
        ];                   
        return {path: path};
    };
    

    现在我们可以使用它来绘制指定厚度的弧线,在我们想要的任何地方开始和结束。

    var redParams = {stroke: "#f00", "stroke-width": 1, fill:"#eee"},
        greenParams = {stroke: "#0f0", "stroke-width": 1, fill:"#eee"},
        blueParams = {stroke: "#00f", "stroke-width": 1, fill:"#eee"},
        cx = 300, cy = 300, innerRadius = 100, outerRadius = 250,
    
    var red = paper.path().attr(redParams).attr({arc: [cx, cy, 0, 90, innerRadius, outerRadius]}); 
    var green = paper.path().attr(greenParams).attr({arc: [cx, cy, 270, 320, innerRadius, outerRadius]}); 
    var blue = paper.path().attr(blueParams).attr({arc: [cx, cy, 95, 220, innerRadius, outerRadius]});
    

    这应该会产生三个灰色的弧线段,带有红色、蓝色和绿色的 1px 边框。

    【讨论】:

    • 我试图在 Raphael 中创建甜甜圈图,而这正是我所需要的!
    【解决方案3】:

    其实自己找到了答案。我首先想到了一些涉及贝塞尔曲线的花哨的东西,但这很有效。

    -> 使用 SVG 路径语法创建路径,与 raphael 一样工作

    function arc(center, radius, startAngle, endAngle) {
        angle = startAngle;
        coords = toCoords(center, radius, angle);
        path = "M " + coords[0] + " " + coords[1];
        while(angle<=endAngle) {
            coords = toCoords(center, radius, angle);
            path += " L " + coords[0] + " " + coords[1];
            angle += 1;
        }
        return path;
    }
    
    function toCoords(center, radius, angle) {
        var radians = (angle/180) * Math.PI;
        var x = center[0] + Math.cos(radians) * radius;
        var y = center[1] + Math.sin(radians) * radius;
        return [x, y];
    }
    

    【讨论】:

    • 我想我会做一个php version,以防有人感兴趣。
    • 不需要自己逼近一个圆。 SVG 已经提供了椭圆路径
    【解决方案4】:

    只是为了消除 user592699 的回答中的一些猜测,这是有效的完整代码:

    <script src="raphael.js"></script>
    <script>
    
      var paper = Raphael(20, 20, 320, 320);
    
      function arc(center, radius, startAngle, endAngle) {
          angle = startAngle;
          coords = toCoords(center, radius, angle);
          path = "M " + coords[0] + " " + coords[1];
          while(angle<=endAngle) {
              coords = toCoords(center, radius, angle);
              path += " L " + coords[0] + " " + coords[1];
              angle += 1;
          }
          return path;
      }
    
      function toCoords(center, radius, angle) {
          var radians = (angle/180) * Math.PI;
          var x = center[0] + Math.cos(radians) * radius;
          var y = center[1] + Math.sin(radians) * radius;
          return [x, y];
      }
    
      paper.path(arc([100, 100], 80, 0, 270));  // draw an arc 
                                                // centered at (100, 100),
                                                // radius 80, starting at degree 0,
                                                // beginning at coordinate (80, 0)
                                                //   which is relative to the center
                                                //   of the circle,
                                                // going clockwise, until 270 degree
    
    </script>
    

    【讨论】:

      【解决方案5】:

      对于那些希望用封闭路径而不是笔划来制作弧线的人,我已经扩展了 genkilabs 的答案来制定解决方案。如果您需要为弧线提供外部笔触,这可能会有所帮助。

      // Custom Arc Attribute, position x&y, value portion of total, total value, Radius, width
      var archtype = Raphael("canvas", 200, 100);
      archtype.customAttributes.arc = function (xloc, yloc, value, total, R, width) {
          if(!width) width = R * 0.4;
          var alpha = 360 / total * value,
              a = (90 - alpha) * Math.PI / 180,
              w = width / 2,
              r1 = R + w,
              r2 = R - w,
              x1 = xloc + r1 * Math.cos(a),
              y1 = yloc - r1 * Math.sin(a),
              x2 = xloc + r2 * Math.cos(a),
              y2 = yloc - r2 * Math.sin(a),
              path;
          if (total == value) {
              path = [
                  ["M", xloc, yloc - r1],
                  ["A", r1, r1, 0, 1, 1, xloc - 0.01, yloc - r1],
                  ["Z"],
                  ["M", xloc - 0.01, yloc - r2],
                  ["A", r2, r2, 0, 1, 0, xloc, yloc - r2],
                  ["Z"]
              ];
          } else {
              path = [
                  ["M", xloc, yloc - r1],
                  ["A", r1, r1, 0, +(alpha > 180), 1, x1, y1],
                  ["L", x2, y2],
                  ["A", r2, r2, 0, +(alpha > 180), 0,  xloc, yloc - r2],
                  ["L", xloc, yloc - r1],
                  ["Z"]
              ];
          }
          return {
              path: path
          };
      };
      
      //make an arc at 50,50 with a radius of 30 that grows from 0 to 40 of 100 with a bounce
      var my_arc = archtype.path().attr({
          "fill": "#00f",
          "stroke": "#f00",
          "stroke-width": 5,
          arc: [50, 50, 0, 100, 30]
      });
      
      my_arc.animate({
          arc: [50, 50, 40, 100, 30]
      }, 1500, "bounce");
      

      JSFiddle

      【讨论】:

        【解决方案6】:

        您也可以在不使用循环的情况下执行此操作。以下实现了这一点,并且也适用于负角。

        作为 r 传入一个 Raphael 对象。角度从 0 度开始,这是圆的顶部,而不是其他几个解决方案中列出的右侧。

                function drawArc(r, centerX, centerY, radius, startAngle, endAngle) {
                    var startX = centerX+radius*Math.cos((90-startAngle)*Math.PI/180); 
                    var startY = centerY-radius*Math.sin((90-startAngle)*Math.PI/180);
                    var endX = centerX+radius*Math.cos((90-endAngle)*Math.PI/180); 
                    var endY = centerY-radius*Math.sin((90-endAngle)*Math.PI/180);
                    var flg1 = 0;
        
                    if (startAngle>endAngle)
                        flg1 = 1;
                    else if (startAngle<180 && endAngle<180)
                        flg1 = 0;
                    else if (startAngle>180 && endAngle>180)
                        flg1 = 0;
                    else if (startAngle<180 && endAngle>180)
                        flg1 = 0; // edited for bugfix here, previously this was 1
                    else if (startAngle>180 && endAngle<180)
                        flg1 = 1;
        
                    return r.path([['M',startX, startY],['A',radius,radius,0,flg1,1,endX,endY]]);
                };
        

        【讨论】:

          【解决方案7】:

          我已经修改了 genkilabs 的答案,包括旋转和倒置能力。此外,环的填充量已更改为单个数字百分比。 (反转改编自this post)。希望对您有所帮助!

          paper.customAttributes.arc = function (xloc, yloc, percent, rad, rot, invert) {
              var alpha = 3.6 * percent,
              a = (90 - alpha) * Math.PI / 180,
              x = xloc + rad * Math.cos(a),
              y = yloc - rad * Math.sin(a),
              path;
          
              if (invert) {
                  x = xloc - rad * Math.cos(a);
              }
          
              if (percent >= 100) {
                  path = [
                      ["M", xloc, yloc - rad],
                      ["A", rad, rad, 0, 1, 1, xloc - 0.01, yloc - rad]
                  ];
              } else {
                  path = [
                      ["M", xloc, yloc - rad],
                      ["A", rad, rad, 0, +(alpha > 180), +(!invert), x, y]
                  ];
                  }
              return {
                  path: path,
                  transform: "r"+rot+","+xloc+","+yloc,
              };
          };
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-06
            • 2017-11-02
            • 2014-11-16
            • 1970-01-01
            相关资源
            最近更新 更多