如何仅使用 stroke-dasharray 而非 stroke-dashoffset 绘制饼图
How can I draw a pie chart only using stroke-dasharray, not stroke-dashoffset
我正在尝试仅使用 stroke-dasharray 和旋转和平移等其他工具绘制饼图,我不允许使用 stroke-dashoffset,因为 wkhtmltopdf 0.12.5 不支持它。我试图做一些类似于下面的代码
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4"
transform="rotate(-90) translate(-20)"/>
</svg>
其中 31.4 是圆的周长,10.99 是周长的 35%。这是绘制一个代表饼图 35% 的切片。我如何在不使用 stroke-dashoffset 的情况下绘制更多切片(例如,一个代表 40%,另一个代表 13%),我无法弄清楚。非常感谢大家的帮助。
不推荐以这种方式创建饼图。通过“那样”,我指的是在笔画宽度与圆的半径相匹配的地方制作圆。准确的说,笔划宽度是圆半径的两倍。
某些浏览器(或浏览器版本)和渲染库在渲染该形式的圆圈时存在错误。推荐的方法是为每个饼图段创建一个路径。
但是,假设您想继续使用此方法,那么您需要了解以下内容。
<circle>
元素上的笔划图案从 3 点开始呈现,并围绕圆圈顺时针进行。
这就是为什么你在上面的例子中有 rotate(-90)
。 -90 度旋转是将圆圈旋转 -90 度,以便笔画从顶部(12 点钟方向)开始。
破折号中的两个数字是<length of dash> <length of gap>
。然后重复该模式。
好的。让我们更新您的 SVG 以添加您请求的额外片段。
首先,我建议进行一些更改:
- 将
rotate(-90)
移动到父组,这样您在计算新切片的旋转时就不必担心它了。
- 如果使用以旋转为中心的
rotate()
版本,您会发现它会容易得多:rotate(angle, centreX, centreY)
.
- 我们需要将填充颜色 (
fill="bisque"
) 添加到一个单独的圆圈中。否则,您添加的每个新段的填充将与之前的段重叠。
所以我们的新起点是:
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
</g>
</svg>
添加 40% 的细分
您需要的笔划长度为 40% of 31.4 = 12.56
。
要旋转它使其从第一段的末尾开始,您需要将它旋转一个等于 (10.99 / 31.4) * 360deg = 126deg
的角度。
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
</g>
</svg>
添加 13% 的细分
您需要的笔划长度为 13% of 31.4 = 4.082
。
要旋转它使其从前一段的末尾开始,您需要将前两段的长度相加,并将其转换为角度。
((10.99 + 12.56) / 31.4) * 360deg = 0.75 * 360 = 270deg`.
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
<circle r="5" cx="10" cy="10"
stroke="cornflowerblue"
stroke-dasharray="4.082 31.4"
transform="rotate(270, 10,10)"/>
</g>
</svg>
我将 Paul 的回答包装在自定义元素中 <svg-pie-chart>
(所有现代浏览器都支持)
通过使用 unknown
元素行为,它简化了 HTML 文档中的用法:
<svg-pie-chart>
<circle r="25%" cx="50%" cy="50%" fill="bisque" />
<segment percent="35" stroke="tomato" />
<segment percent="40" stroke="goldenrod" />
<segment percent="13" stroke="cornflowerblue" />
<circle r="2" cx="10" cy="10" fill="green" />
</svg-pie-chart>
<style>
svg-pie-chart svg {
width: 180px;
background: grey;
}
</style>
<script>
customElements.define("svg-pie-chart", class extends HTMLElement {
connectedCallback() {
setTimeout(() => { // wait till all children are (unknown) Elements
let rotate = 0;
let svg = [...this.querySelectorAll("*")].map(el => {
let elsvg = el.outerHTML;
if (el.nodeName == "SEGMENT") {
let [percent, stroke, deg = percent.value * .3142] = el.attributes;
elsvg = `<circle r='5' cx='10' cy='10' stroke='${stroke.value}'` +
` stroke-dasharray='${deg} 31.42' transform="rotate(${rotate} 10 10)"/>`;
rotate += (deg / 31.42) * 360;
}
return elsvg;
});
this.innerHTML=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>` +
`<g transform='rotate(-90 10 10)' fill='none' stroke-width='10'></g></svg>`;
this.querySelector("g").innerHTML = svg.join``;
})}});
</script>
我正在尝试仅使用 stroke-dasharray 和旋转和平移等其他工具绘制饼图,我不允许使用 stroke-dashoffset,因为 wkhtmltopdf 0.12.5 不支持它。我试图做一些类似于下面的代码
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4"
transform="rotate(-90) translate(-20)"/>
</svg>
其中 31.4 是圆的周长,10.99 是周长的 35%。这是绘制一个代表饼图 35% 的切片。我如何在不使用 stroke-dashoffset 的情况下绘制更多切片(例如,一个代表 40%,另一个代表 13%),我无法弄清楚。非常感谢大家的帮助。
不推荐以这种方式创建饼图。通过“那样”,我指的是在笔画宽度与圆的半径相匹配的地方制作圆。准确的说,笔划宽度是圆半径的两倍。
某些浏览器(或浏览器版本)和渲染库在渲染该形式的圆圈时存在错误。推荐的方法是为每个饼图段创建一个路径。
但是,假设您想继续使用此方法,那么您需要了解以下内容。
<circle>
元素上的笔划图案从 3 点开始呈现,并围绕圆圈顺时针进行。这就是为什么你在上面的例子中有
rotate(-90)
。 -90 度旋转是将圆圈旋转 -90 度,以便笔画从顶部(12 点钟方向)开始。破折号中的两个数字是
<length of dash> <length of gap>
。然后重复该模式。
好的。让我们更新您的 SVG 以添加您请求的额外片段。
首先,我建议进行一些更改:
- 将
rotate(-90)
移动到父组,这样您在计算新切片的旋转时就不必担心它了。 - 如果使用以旋转为中心的
rotate()
版本,您会发现它会容易得多:rotate(angle, centreX, centreY)
. - 我们需要将填充颜色 (
fill="bisque"
) 添加到一个单独的圆圈中。否则,您添加的每个新段的填充将与之前的段重叠。
所以我们的新起点是:
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
</g>
</svg>
添加 40% 的细分
您需要的笔划长度为 40% of 31.4 = 12.56
。
要旋转它使其从第一段的末尾开始,您需要将它旋转一个等于 (10.99 / 31.4) * 360deg = 126deg
的角度。
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
</g>
</svg>
添加 13% 的细分
您需要的笔划长度为 13% of 31.4 = 4.082
。
要旋转它使其从前一段的末尾开始,您需要将前两段的长度相加,并将其转换为角度。
((10.99 + 12.56) / 31.4) * 360deg = 0.75 * 360 = 270deg`.
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
<circle r="5" cx="10" cy="10"
stroke="cornflowerblue"
stroke-dasharray="4.082 31.4"
transform="rotate(270, 10,10)"/>
</g>
</svg>
我将 Paul 的回答包装在自定义元素中 <svg-pie-chart>
(所有现代浏览器都支持)
通过使用 unknown
元素行为,它简化了 HTML 文档中的用法:
<svg-pie-chart>
<circle r="25%" cx="50%" cy="50%" fill="bisque" />
<segment percent="35" stroke="tomato" />
<segment percent="40" stroke="goldenrod" />
<segment percent="13" stroke="cornflowerblue" />
<circle r="2" cx="10" cy="10" fill="green" />
</svg-pie-chart>
<style>
svg-pie-chart svg {
width: 180px;
background: grey;
}
</style>
<script>
customElements.define("svg-pie-chart", class extends HTMLElement {
connectedCallback() {
setTimeout(() => { // wait till all children are (unknown) Elements
let rotate = 0;
let svg = [...this.querySelectorAll("*")].map(el => {
let elsvg = el.outerHTML;
if (el.nodeName == "SEGMENT") {
let [percent, stroke, deg = percent.value * .3142] = el.attributes;
elsvg = `<circle r='5' cx='10' cy='10' stroke='${stroke.value}'` +
` stroke-dasharray='${deg} 31.42' transform="rotate(${rotate} 10 10)"/>`;
rotate += (deg / 31.42) * 360;
}
return elsvg;
});
this.innerHTML=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>` +
`<g transform='rotate(-90 10 10)' fill='none' stroke-width='10'></g></svg>`;
this.querySelector("g").innerHTML = svg.join``;
})}});
</script>