【问题标题】:SVG Draw a circle with 4 sectorsSVG画一个有4个扇区的圆
【发布时间】:2020-12-30 01:21:29
【问题描述】:

我需要画一个有 4 个扇区的圆圈。我正在尝试绘制这样的扇区:

<path d="M200, 200, l 100,-100 a180,180 0 0,0 -127.27,127.27 z"/>

我从方程式中得到 -127.27、127.27:

x=cos(angle) * radius
y=sin(angle) * radius

我的角度是 135,我的半径是 180。

这是我得到的codepen。蓝色的是我在这里说的,黑色的是我正在尝试使用不同的数字。

为什么我没有得到正确的 1/4 圆?我错过了什么?

【问题讨论】:

    标签: html svg trigonometry


    【解决方案1】:

    这些数字没有多大意义。首先移动到(200,200),然后画一条直线到(300,100)(长度:141 个单位),然后画一条圆弧,结束于(172.73,227.27)(半径180 个单位)。直线段的长度不应该至少等于圆的半径吗?

    你让自己的生活变得非常困难。如果要绘制四个圆弧段,第一步是使用&lt;g&gt; 元素将坐标系移动到圆心。然后,您可以使用几乎相同的代码创建所有四个段。

    这是一个例子:

    <svg width="200" height="200" viewBox="0 0 200 200">
      <g transform="translate(100,100)" stroke="#000" stroke-width="2">
        <path d="M0 0-70 70A99 99 0 0 1-70-70Z" fill="#f00"/>
        <path d="M0 0-70-70A99 99 0 0 1 70-70Z" fill="#080"/>
        <path d="M0 0 70-70A99 99 0 0 1 70 70Z" fill="#dd0"/>
        <path d="M0 0 70 70A99 99 0 0 1-70 70Z" fill="#04e"/>
      </g>
    </svg>

    如果您想要一个具有不同半径的圆,请将99 替换为您想要的半径,并将70 替换为此值乘以 sqrt(0.5)。

    路径数据分解:

    M0 0-70 70
    

    Move(0,0),然后画一条直线到(-70,70)(隐含L)。

    A99 99 0 0 1-70-70
    

    使用rx=rx=99x-axis-rotation=0large-arc-flag=1sweep-flag=0 从该点绘制elliptical arc(-70,-70)。 (最后两个参数描述here)。

    Z
    

    Close 路径。

    【讨论】:

    • 您能告诉我更多信息,以便我了解实际发生的情况吗?这将中心置于 100,100,对吗?而M0 0-70 70又是做什么的呢?
    【解决方案2】:

    我真的很懒,所以当我需要绘制弧线时,我会使用以下脚本: 我创建一个单位向量:

    var p = svgElem.createSVGPoint()
    p.x = 0
    p.y = 1
    

    然后我为我的旋转创建一个矩阵:

    var m = svgElem.createSVGMatrix()
    

    最后我旋转单位向量并将其平移/缩放到我想要的位置。

    var p2 = p.matrixTransform(m.rotate(45))
    p2.x = cx + p2.x*rx
    p2.y = cy + p2.y*ry
    

    如果我想硬编码段,现在我可以console.log(p2.x,p2.y),或者你可以从脚本创建段。

    这是一个基本示例(我知道,对于像上面这样的简单案例,这不是必需的,但它是一个简单的通用解决方案,在过去几年对我有很大帮助......)

    var svgElem=document.getElementById("svg");
    var cx=100;
    var cy=100;
    var rx=90;
    var ry=90;
    
    var p = svgElem.createSVGPoint();
        p.x = 0;
        p.y = 1;
    
    
    var m = svgElem.createSVGMatrix();
    
    
    var p2 = p.matrixTransform(m.rotate(45));
        p2.x = cx + p2.x*rx;
        p2.y = cy + p2.y*ry;
        
        console.log(p2.x,p2.y);
    
    var path = document.createElementNS("http://www.w3.org/2000/svg","path");
        svgElem.appendChild(path);
    var d="M"+cx+" "+(cy+ry)+"A"+rx+" "+ry+" 0 0 1"+p2.x+" "+p2.y+"L"+cx+" "+cy+"z";
        path.setAttribute("d",d)
    <svg id="svg" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
      
    </svg>

    【讨论】:

      【解决方案3】:

      这是我在React组件中使用的SVG扇区路径的编程生成函数:

      getSectorPath(x, y, outerDiameter, a1, a2) {
          const degtorad = Math.PI / 180;
          const halfOuterDiameter = outerDiameter / 2;
          const cr = halfOuterDiameter - 5;
          const cx1 = (Math.cos(degtorad * a2) * cr) + x;
          const cy1 = (-Math.sin(degtorad * a2) * cr) + y;
          const cx2 = (Math.cos(degtorad * a1) * cr) + x;
          const cy2 = (-Math.sin(degtorad * a1) * cr) + y;
      
          return "M" + x + " " + y + " " + cx1 + " " + cy1 + " A" + cr + " " + cr + " 0 0 1 " + cx2 + " " + cy2 + "Z";
      }
      

      这是用法:

      <svg width={outerDiameter} height={outerDiameter}>
          <path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 45, 135)} fill="#f00"/>
          <path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 135, 225)} fill="#f00"/>
          <path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 225, 315)} fill="#f00"/>
          <path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 315, 45)} fill="#f00"/>
      </svg>
      

      【讨论】:

      • 非常有用的功能,我只会将最后一行更改为:return `M${x} ${y} ${cx1} ${cy1} A${cr} ${cr} 0 0 1 ${cx2} ${cy2}Z`;
      【解决方案4】:

      这是我从 JavaScript 创建 svg 的示例。我写它的灵感来自@zmechanic 的回答。一个扇区有梯度。 要执行它,只需创建一个 html 文档并复制内容。

      <!DOCTYPE html>
      <html>
        <body>
          <div id="svgRoot"></div>
          <script type="text/javascript">
            const DIAMETER = 200;
            const SVG_SIZE = DIAMETER + 12;
            const STROKE = "black";
            const STROKE_WIDTH = "2";
      
            const getSectorPath = (x, y, outerDiameter, a1, a2) => {
              const degtorad = Math.PI / 180;
              const cr = outerDiameter / 2;
              const cx1 = Math.cos(degtorad * a2) * cr + x;
              const cy1 = -Math.sin(degtorad * a2) * cr + y;
              const cx2 = Math.cos(degtorad * a1) * cr + x;
              const cy2 = -Math.sin(degtorad * a1) * cr + y;
      
              return `M${x} ${y} ${cx1} ${cy1} A${cr} ${cr} 0 0 1 ${cx2} ${cy2}Z`;
            };
      
            const svgRoot = document.getElementById("svgRoot");
            const pieChartSvgString = `<svg width="${SVG_SIZE}" height="${SVG_SIZE}">
              <defs>
                <linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="0%">
                  <stop offset="0%" style="stop-color:#DD5E89;stop-opacity:1" />
                  <stop offset="100%" style="stop-color:#F7BB97;stop-opacity:1" />
                </linearGradient>
              </defs>
              <g fill="url(#gradient1)">
                <path
                  stroke="${STROKE}"
                  strokeWidth="${STROKE_WIDTH}"
                  d="${getSectorPath(SVG_SIZE / 2, SVG_SIZE / 2 - 5, DIAMETER, 45, 135)}"
                />
              </g>
              <path
                stroke="${STROKE}"
                strokeWidth="${STROKE_WIDTH}"
                d="${getSectorPath(SVG_SIZE / 2, SVG_SIZE / 2, DIAMETER, 135, 225)}"
                fill="#00ff00"
              />
              <path
                stroke="${STROKE}"
                strokeWidth="${STROKE_WIDTH}"
                d="${getSectorPath(SVG_SIZE / 2, SVG_SIZE / 2, DIAMETER, 225, 315)}"
                fill="#0000ff"
              />
              <path
                stroke="${STROKE}"
                strokeWidth="${STROKE_WIDTH}"
                d="${getSectorPath(SVG_SIZE / 2, SVG_SIZE / 2, DIAMETER, 315, 45)}"
                fill="#ffff00"
              />
            </svg>`;
            const svgNode = document.createRange().createContextualFragment(pieChartSvgString);
            svgRoot.appendChild(svgNode);
          </script>
        </body>
      </html>

      【讨论】:

        猜你喜欢
        • 2021-01-03
        • 2017-01-16
        • 2020-03-24
        • 1970-01-01
        • 2014-07-03
        • 2014-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多