使用圆形元素的饼图

Ima*_*mad 2 html css svg stroke-dasharray

circle我正在尝试使用中的元素创建饼图svg。我可以将值填充到 60%、30% 和 10%,但所有圆圈都从同一位置开始。

如何使下一个循环从上一个循环结束的地方开始?

svg { transform: rotate(-90deg); }

circle {
  stroke-width: 3;
  stroke-opacity: 1;
  fill: none; 
}

circle.stroke-yellow {
  stroke: yellow;
  stroke-dasharray: calc(2*3.14*50*60/100),calc(2*3.14*50);    
}

circle.stroke-red {
  stroke: red;
  stroke-dasharray: calc(2*3.14*50*30/100),calc(2*3.14*50);  
}

circle.stroke-blue {
  stroke: blue;
  stroke-dasharray: calc(2*3.14*50*10/100),calc(2*3.14*50);  
}
Run Code Online (Sandbox Code Playgroud)
<svg xmlns="http://www.w3.org/2000/svg" height="220">
    <circle class="stroke-yellow" cy="110"  cx="110" r="50"></circle>
    <circle class="stroke-red" cy="110" cx="110" r="50"></circle>
    <circle class="stroke-blue" cy="110" cx="110" r="50"></circle>
</svg>
Run Code Online (Sandbox Code Playgroud)

我在 CSS 中提到的也stroke-width不起作用。

her*_*zel 5

正如 @enxaneta 提到的:您需要通过更改dash-offset属性来为每个饼图部分提供一个偏移量。

\n

根据您的代码示例:

\n

\r\n
\r\n
svg {\n  transform: rotate(-90deg);\n}\n\ncircle {\n  stroke-width: 3;\n  stroke-opacity: 1;\n  fill: none;\n}\n\n.stroke {\n  stroke-width: 100;\n  --circumference: 314.159\n}\n\ncircle.stroke-blue {\n  stroke: blue;\n  stroke-dasharray: calc( var(--circumference) * 10 / 100), var(--circumference);\n  stroke-dashoffset: 0;\n}\n\ncircle.stroke-red {\n  stroke: red;\n  stroke-dasharray: calc( var(--circumference) * 30 / 100), var(--circumference);\n  stroke-dashoffset: calc( 0 - var(--circumference) * 10 / 100);\n}\n\ncircle.stroke-yellow {\n  stroke: yellow;\n  stroke-dasharray: calc( var(--circumference) * 60 / 100), var(--circumference);\n  stroke-dashoffset: calc( 0 - var(--circumference) * 40 / 100);\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 220" height="220">\n      <circle class="stroke stroke-blue stroke-10" cy="110" cx="110" r="50" />\n    <circle class="stroke stroke-yellow stroke-60" cy="110"  cx="110" r="50" />\n    <circle class="stroke stroke-red stroke-30" cy="110" cx="110" r="50" />\n</svg>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

stroke-width需要为“100”(半径*2);

\n

缺点:

\n\n

建议:

\n
    \n
  • 通过优化 svg 几何形状来简化计算。
  • \n
  • 通过 HTML/svg 属性(或 css 变量)控制您的值(例如饼图百分比、颜色)
  • \n
\n

显示 2 个略有不同的 svg 设置的示例:

\n

\r\n
\r\n
body{\n  font-family: arial;\n  font-size:10px;\n}\n.icon-wrp {\n  position: relative;\n  display: inline-block;\n  width: 200px;\n  vertical-align: top;\n}\n\n.icon-wrp p{\n  font-size:12px;\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<!--simple pi -->\n<div class="icon-wrp">\n  <svg class="svgPieAsset" viewBox="0 0 63.6619772368 63.6619772368">\n    <symbol id="slice">\n      <circle transform="rotate(-90 31.8309886184 31.8309886184)" id="circle" class="percent" cx="50%" cy="50%" r="15.9154943092" fill="none" stroke-width="31.8309886184" />\n    </symbol>\n    <!--actual pi slices -->\n    <use class="segment" href="#slice" stroke="green" stroke-dashoffset="0" stroke-dasharray="30 100" />\n    <use class="segment" href="#slice" stroke="orange" stroke-dashoffset="-30" stroke-dasharray="60 100" />\n    <use class="segment" href="#slice" stroke="purple" stroke-dashoffset="-90" stroke-dasharray="10 100" />\n  </svg>\n  <p>1. Precice geometry based on PI. <br>Should be rendered fine on all browsers.</p>\n</div>\n\n\n<div class="icon-wrp">\n  <svg class="svgPieAsset" viewBox="0 0 100 100">\n    <symbol id="slice2">\n      <circle transform="rotate(-90 50 50)" id="circle" class="percent" cx="50%" cy="50%" r="25" fill="none" stroke-width="50%" pathLength="100" />\n    </symbol>\n    <!--actual pi slices -->\n    <use class="segment" href="#slice2" stroke="green" stroke-dashoffset="0" stroke-dasharray="30 100" />\n    <use class="segment" href="#slice2" stroke="orange" stroke-dashoffset="-30" stroke-dasharray="60 100" />\n    <use class="segment" href="#slice2" stroke="purple" stroke-dashoffset="-90" stroke-dasharray="10 100" />\n  </svg>\n  <p>2. Using pathLength="100". <br>Might show a tiny gap on chromium based browsers.</p>\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

1. 左示例:正在使用精确的(基于 PI 的)圆形几何图形
\n圆形元素所需的周长应为 100 svg 单位。
\n因此我们需要像这样设置理想值:

\n

半径: 15.91549430919 (100/2\xcf\x80)
\n描边宽度: 31.8309886184 (2 r)
\n vieBox 宽度/高度: 63.6619772368 (4
r)

\n

2. 右例:使用pathLength="100"
\n PathLength允许我们通过将路径的长度计算值设置为“100”来使用任何圆尺寸。
\n不幸的是,您可能会在某些浏览器(例如基于 Chromium 的浏览器)上遇到渲染不精确的情况,从而导致饼图片段之间出现明显的间隙。

\n

渲染不精确

\n

这个问题很可能会在未来版本的 chromium 中得到解决。

\n

显示饼图段
\n无论怎样,您现在可以通过设置笔画虚线长度值轻松显示基于百分比的饼图段/切片:

\n

示例 30% 破折号长度;抵消。0(因为它是第一段):

\n
  <circle stroke-dashoffset="0" stroke-dasharray="30 100" cx="50%" cy="50%" r="15.9154943092" fill="none" stroke-width="31.8309886184"  />\n
Run Code Online (Sandbox Code Playgroud)\n

添加饼图分段:
\n您需要通过减去之前的破折号长度(百分比)来逐步递减(因为我们需要负值)破折号偏移值:
\n0、-30、-90

\n

示例:60% 破折号长度;抵消。-30

\n
  <circle stroke-dashoffset="-30" stroke-dasharray="60 100" cx="50%" cy="50%" r="15.9154943092" fill="none" stroke-width="31.8309886184"  />\n
Run Code Online (Sandbox Code Playgroud)\n

针对可重用性进行优化的示例(使用 css 变量)

\n

\r\n
\r\n
  <circle stroke-dashoffset="0" stroke-dasharray="30 100" cx="50%" cy="50%" r="15.9154943092" fill="none" stroke-width="31.8309886184"  />\n
Run Code Online (Sandbox Code Playgroud)\r\n
  <circle stroke-dashoffset="-30" stroke-dasharray="60 100" cx="50%" cy="50%" r="15.9154943092" fill="none" stroke-width="31.8309886184"  />\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

编辑:圆环图示例
\n对于圆环图或圆形仪表\xe2\x80\x93,只需根据需要调整笔画宽度。

\n

\r\n
\r\n
.icon-wrp {\n  position: relative;\n  display: inline-block;\n  width: 200px;\n  vertical-align: top;\n}\n\n.chart {\n  width: 1em;\n  height: 1em;\n  font-size: var(--chartFontSize);\n}\n\n.segment {\n  stroke-dasharray: var(--percent) 100;\n  stroke-dashoffset: var(--offset);\n  stroke: var(--strokeColor);\n}\n\n.chartAni .segment {\n  animation-name: progress;\n  animation-fill-mode: forwards;\n  animation-delay: 0.3s;\n  animation-duration: 0.5s;\n  transition: 0.3s;\n  stroke-dasharray: 0 100;\n}\n\n@keyframes progress {\n  from {\n    stroke-dasharray: 0 100;\n    stroke-dashoffset: 0;\n  }\n  to {\n    stroke-dasharray: var(--percent) 100;\n    stroke-dashoffset: var(--offset);\n  }\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<!-- pie asset \xe2\x80\x93 hidden -->\n<svg class="svgPieAsset" style="display:none" viewBox="0 0 63.6619772368 63.6619772368">\n  <symbol id="slice" viewBox="0 0 63.6619772368 63.6619772368">\n    <circle transform="rotate(-90 31.8309886184 31.8309886184)" id="circle" class="percent" cx="31.8309886184" cy="31.8309886184" r="15.9154943092" fill="none" stroke-width="31.8309886184" />\n  </symbol>\n</svg>\n\n<!-- visible pie chart -->\n<div class="icon-wrp">\n  <svg id="pieChart01" class="chart chartAni" style="--chartFontSize:20vw">\n    <use class="segment" href="#slice" style="--offset:-0; --percent:33.333; --strokeColor:green" />\n    <use class="segment" href="#slice" style="--offset:-33.333; --percent:33.333; --strokeColor:purple" />\n    <use class="segment" href="#slice" style="--offset:-66.666; --percent:33.333; --strokeColor:gray" />\n  </svg>\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

  • @Imad:啊,你可以在你的描述中添加标签“donut-chart”。不过,基本上是一样的。您只需根据需要调整笔划宽度(并根据它,viewBox 就会有一个相当裁剪的图表) (2认同)

ray*_*eld 5

如果由于某种原因,herrstrietzel 的回答未能解决您的问题:

\n

曾几何时,我开始撰写一篇博客文章,演示如何在 React 中生成简单的 SVG 圆环图/饼图。它并不完整,但它包含了计算在图表中绘制每个线段的路径所需的所有信息。

\n

这篇文章本身是以 React 为中心的,但方法不需要 React。

\n

下面的代码片段是使用该博客文章中的演示生成的。

\n

\r\n
\r\n
:root {\n  --color1: #6761a8;\n  --color2: #009ddc;\n  --color3: #f26430;\n}\n\nsvg {\n  max-width: 180px;\n}\n\npath:nth-child(3n + 1) {\n  fill: var(--color1);\n}\n\npath:nth-child(3n + 2) {\n  fill: var(--color2);\n}\n\npath:nth-child(3n + 3) {\n  fill: var(--color3);\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<svg viewBox="0 0 100 100">\n   <path d="M50.99977962889557 22.51817981476399 L50.99993333466665 0.009999666671113516 A50 50 0 1 1 21.909411013411578 91.36325434956197 L34.92449717574351 72.99954813894905 A27.5 27.5 0 1 0 50.99977962889557 22.51817981476399"></path>\n   <path d="M33.293128455589205 71.84331575559345 L20.27779148719977 90.20684420744341 A50 50 0 0 1 19.110270928347777 10.683023540969941 L32.65908657059322 28.656553196968876 A27.5 27.5 0 0 0 33.293128455589205 71.84331575559345"></path>\n   <path d="M34.25580929035654 27.45292793069627 L20.707239127704607 9.479213229769087 A50 50 0 0 1 49.000066665333264 0.009999666671113516 L49.00022037110441 22.51817981476399 A27.5 27.5 0 0 0 34.25580929035654 27.45292793069627"></path>\n</svg>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n


\n

计算路径

\n

每个<path>代表图表的一个片段(切片)。

\n

要绘制线段,您需要计算 4 个角的坐标并用直线和圆弧将它们连接起来。

\n

计算坐标

\n

给定角度、半径和中心点,您可以通过以下公式计算 (x, y) 坐标:

\n
function getCoordinate(angleInDegrees, radius, center = 50) {\n  // degrees to radians;\n  const radians = angleInDegrees * (Math.PI / 180);\n\n  const x = center - Math.cos(radians) * radius\n  const y = center - Math.sin(radians) * radius;\n\n  return [x, y];\n}\n
Run Code Online (Sandbox Code Playgroud)\n

因此,对于外半径为 50、内半径为 20 的 90\xc2\xb0 线段,您可以通过以下方式获取角坐标:

\n
const radiusOuter = 50;\nconst radiusInner = 20;\nconst angleStart = 0;\nconst angleEnd = 90;\n\nconst [x1, y1] = getCoordinate(angleStart, radiusInner); // starting angle on inner radius\nconst [x2, y2] = getCoordinate(angleStart, radiusOuter); // starting angle on outer radius\nconst [x3, y3] = getCoordinate(angleEnd, radiusOuter); // ending angle on outer radius\nconst [x4, y4] = getCoordinate(angleEnd, radiusInner); // ending angle on inner radius\n
Run Code Online (Sandbox Code Playgroud)\n

圆环段上的坐标位置

\n

使用 SVG 路径命令连接坐标:

\n

有关下面使用的每个路径命令的详细信息可以在 MDN 中找到。

\n
const largeArc = 0; // percent > 0.5 ? 1 : 0;\nconst sweepOuter = 1;\nconst sweepInner = 0;\n\nconst commands = [\n  // move to start angle coordinate, inner radius (1)\n  `M${x1} ${y1}`,\n\n  // line to start angle coordinate, outer radius (2)\n  `L${x2} ${y2}`,\n\n  // arc to end angle coordinate, outer radius (3)\n  `A${radiusOuter} ${radiusOuter} 0 ${largeArc} ${sweepOuter} ${x3} ${y3}`,\n\n  // line to end angle coordinate, inner radius (4)\n  `L${x4} ${y4}`,\n\n  // arc back to start angle coordinate, inner radius (1)\n  `A${radiusInner} ${radiusInner} 0 ${largeArc} ${sweepInner} ${x1} ${y1}`\n];\n
Run Code Online (Sandbox Code Playgroud)\n

将其放入 SVG 中并添加一些 css,您就得到了片段:

\n

\r\n
\r\n
svg {\n  width: 250px;\n  border: 1px solid grey;\n}\n\npath {\n  fill: tomato;\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<svg viewBox="0 0 100 100">\n  <path d="\n    M30 50\n    L0 50\n    A50 50 0 0 1 50 0\n    L50 30\n    A20 20 0 0 0 30 50\n  "/>\n</svg>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

对其他段重复此操作。

\n