【问题标题】:Creating a static pie chart with CSS使用 CSS 创建静态饼图
【发布时间】:2020-07-15 22:15:54
【问题描述】:

我正在尝试使用 css 和 html 创建一个饼图。我只是显示一些静态数字,因此我尽量保持相对简单,不使用任何动画。

我目前在如何创建我想要的外观方面遇到了障碍。下面的代码 sn-p 完全按照我的意愿工作,问题是 conic-gradient 不受 firefox 和 Internet Explorer 支持,这将是该项目的一个问题。

.progress-circle {
  --d: 50px;
  --color: #002F65;
  --progress: 40;
  border-radius: var(--d);
  height: var(--d);
  width: var(--d);
  background: conic-gradient( var(--color) calc(calc(var(--progress) / 100) * 360deg), transparent calc(calc(var(--progress) / 100) * 360deg));
}
<div class="progress-circle"></div>

我一直在寻找类似于上面示例的替代方法,这使我看到了这篇文章:designing simple pie charts with css

我的问题是计算饼图百分比增长的方式似乎与我想要完成的事情不兼容。因为它是由transform: rotate(.1turn);确定的

我的主要问题是可以使conic-gradient 与其他浏览器兼容吗?如果不是,那么使用 css 制作饼图以与第一个示例非常相似的最佳方法是什么?

对于上下文,我将从数组中传递数据以确定饼图的百分比。

.pie {
  width: 100px; height: 100px;
  border-radius: 50%;
  background: yellowgreen;
  background-image:
  linear-gradient(to right, transparent 50%, #655 0);
}

.pie::before {
  content: "";
  display: block;
  margin-left: 50%;
  height: 100%;
  border-radius: 0 100% 100% 0 / 50%;
  background: #655;
  transform-origin: left;
  transform: rotate(.1turn);
}
<div class="pie"></div>

【问题讨论】:

  • 检查这个:stackoverflow.com/a/52205730/8620333(去掉顶层,你得到你想要的)
  • @TemaniAfif 感谢您的回复。您的示例对我正在寻找的内容有所帮助,但我有几个问题,因为您是发布答案的人。我将如何传递百分比值?例如,这似乎是由学位决定的;如果我想通过40% 覆盖 40% 。我提供了一个 jsfiddle 链接作为示例:jsfiddle.net/94jrmkdc/20

标签: html css charts


【解决方案1】:

这是一个基于this previous answer的想法

.box {
  /* percentage to degree
    --s:0 for [0% 50%]
    --s:1 for [50% 100%]
   */
  --v:calc( ((18/5) * var(--p) - 90)*1deg);

  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  background:
    linear-gradient(var(--v), yellowgreen 50%,transparent 0) 0 /calc((1 - var(--s))*100%),
    linear-gradient(var(--v), transparent 50%,#655        0) 0 /calc(var(--s)*100%),
    linear-gradient(to right, yellowgreen 50%,#655 0);
}
<div class="box" style="--p:5;--s:0"></div>
<div class="box" style="--p:20;--s:0"></div>
<div class="box" style="--p:50;--s:0"></div>
<div class="box" style="--p:70;--s:1"></div>
<div class="box" style="--p:95;--s:1"></div>

我们可以使用min()优化代码,只使用一个变量,但需要注意支持:https://caniuse.com/#feat=css-math-functions

.box {
  /* percentage to degree  */
  --v:calc( ((18/5) * var(--p) - 90)*1deg);

  width:100px;
  height:100px;
  display:inline-block;
  border-radius:50%;
  background:
    linear-gradient(var(--v), yellowgreen 50%,transparent 0) 0 /min(100%,(50 - var(--p))*100%),
    linear-gradient(var(--v), transparent 50%,#655        0) 0 /min(100%,(var(--p) - 50)*100%),
    linear-gradient(to right, yellowgreen 50%,#655 0);
}
<div class="box" style="--p:5;"></div>
<div class="box" style="--p:20;"></div>
<div class="box" style="--p:50;"></div>
<div class="box" style="--p:70;"></div>
<div class="box" style="--p:95;"></div>

另一个使用更多支持的伪元素的想法:

.box {
  /* percentage to degree  */
  --v: calc( ((18/5) * var(--p) - 180)*1deg);
  
  width: 100px;
  display: inline-flex;
  border-radius: 50%;
  overflow: hidden;
  background: linear-gradient(to right, yellowgreen 50%, #655 0);
}

.box::before,
.box::after {
  content: "";
  width: 50%;
  padding-top:100%;
  transform: rotate(var(--v));
}

.box::before {
  background: 
    linear-gradient(yellowgreen 0 0) 
    0 / calc((50 - var(--p))*1%);
  transform-origin: right;
}

.box::after {
  background: 
    linear-gradient(#655 0 0)       
    0 / calc((var(--p) - 50)*1%);
  transform-origin: left;
}
<div class="box" style="--p:5;"></div>
<div class="box" style="--p:20;width:150px;"></div>
<div class="box" style="--p:50;width:120px;"></div>
<div class="box" style="--p:70;"></div>
<div class="box" style="--p:95;width:80px;"></div>

【讨论】:

  • 只是为了澄清你的答案,如果“风格”大于 50%,我需要使用 --s:1 才能通过 50%;从 0-50% 我会使用 --s:0 理解正确吗?
  • @stepheniok 是的,正确。我正在尝试找到一种优化来避免使用 --s
  • @stepheniok 添加了另一个想法
  • 感谢您详细解释并提供多个示例
【解决方案2】:

CSS 解决方案

基于更改stroke-dasharray属性的参数

要根据扇形的张角设置所需的属性值,需要计算所选半径处的总周长。

假设半径是 50px

let radius = 50;
 let circumference = radius * 2 * Math.PI;
 console.log(circumference );

全围~= 314px

例如,绘制一个等于四分之一圆的线段:

计算破折号的长度:314 * 0.25 = 78.5px

间隙长度:314 * 0.75 = 235.5px

stroke-dasharray 的公式:stroke-dasharray="78.5, 235.5"

类似地,为扇区的其他角设置stroke-dasharray参数。

circle {
fill:#665555;
} 
#p15,#p90,#p180,#p270 {
fill:none;
stroke:#9ACD32;
stroke-width:100;
}
#p15 {
stroke-dasharray:15.7,298.3;
}
#p90 {
stroke-dasharray:78.5,235.5;
}
#p180 {
stroke-dasharray:157,157;
}
#p270 {
stroke-dasharray:235.5,78.5;
}
<svg width="200" height="200" style="border:1px solid">
   <circle id="bg" r="100" cx="100" cy="100"  />  
       
   <path id="p15"    d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50">
  </path>
</svg>   
           <!-- 90deg -->
   <svg width="200" height="200" style="border:1px solid">
       <circle  r="100" cx="100" cy="100" />  
            
       <path id="p90"  stroke-dasharray="78.5,235.5"  d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50">
       </path>
   </svg> 
           <!-- 180deg -->
   <svg width="200" height="200" style="border:1px solid">
       <circle  r="100" cx="100" cy="100"  />  
            
       <path id="p180"  d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50">
       </path>
   </svg>   
           <!-- 270deg -->
<svg width="200" height="200" style="border:1px solid">
       <circle  r="100" cx="100" cy="100"  />  
            
       <path id="p270"    d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50">
       </path>
</svg>

SVG 解决方案

如示例中的CSS solution 使用更改stroke-dasharray 属性

<svg width="200" height="200">
  <circle id="bg" r="100" cx="100" cy="100"  fill="#665555"/> 
 
  <path stroke-dasharray="300 14" stroke-dashoffset="300" d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50" id="p1" 
     r="50" cx="100" cy="100" stroke="#9ACD32" stroke-width="100" fill="none"  >
  </path>
 </svg>
   <svg width="200" height="200">
      <circle  r="100" cx="100" cy="100"  fill="#665555"/> 
          <path stroke-dasharray="235.5 78.5" stroke-dashoffset="235.5" d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50" stroke="#9ACD32" stroke-width="100" fill="none" > 
          </path>
   </svg> 
<svg width="200" height="200">
      <circle id="bg" r="100" cx="100" cy="100"  fill="#665555"/> 
          <path stroke-dasharray="157 157" stroke-dashoffset="157" d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50"  stroke="#9ACD32" stroke-width="100" fill="none"  >
      </path>
</svg>  
    <svg width="200" height="200">
      <circle id="bg" r="100" cx="100" cy="100"  fill="#665555"/> 
          <path stroke-dasharray="78.5 235.5" stroke-dashoffset="78.5" d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50"  stroke="#9ACD32" stroke-width="100" fill="none"  >
      </path>
    </svg>   

一个交互式改变扇形角度的例子

作者的愿望:

对于上下文,我将从数组传递数据以确定 饼图的百分比。

此过程使用inputjavascript 建模:

  1. 显示填充图表的百分比

let circumference = 50 * 2 * Math.PI,
 input = document.querySelector("[type='range']"),
 txt = document.querySelector("#txt1");

input.addEventListener("input",()=>{  
  pieChart();  
})

window.addEventListener("load",()=>{  
  pieChart();  
})

function pieChart(){
  let val = Number(input.value);
  let dash = circumference * val / 100;
  let gap = circumference - dash;
  p15.style.strokeDasharray = dash + " " + gap
txt.innerHTML = (val + '%'); 
}
<div><input id="size" step="1" type="range" min="0" max = "100" value="0" /></div>
<svg width="200" height="200" >
   <circle id="bg" r="100" cx="100" cy="100"  fill="#665555"/>  
       
   <path id="p15"  stroke-dasharray="15.7,298.3"  d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50" id="p1" fill="none" stroke="#9ACD32" stroke-width="100" >
  </path> 
   <text id="txt1" y="60%" x="50%"  text-anchor="middle" font-size="32px" fill="white">0</text>
</svg>   
    
  1. 图表填充角度输出

let circumference = 50 * 2 * Math.PI,
 input = document.querySelector("[type='range']"),
 txt = document.querySelector("#txt1");

input.addEventListener("input",()=>{  
  pieChart();  
})

window.addEventListener("load",()=>{  
  pieChart();  
})

function pieChart(){
  let val = Number(input.value);
  let dash = circumference * val / 360;
  let gap = circumference - dash;
  p15.style.strokeDasharray = dash + " " + gap
txt.innerHTML = (val); 
}
<div><input id="size" step="1" type="range" min="0" max = "360" value="0" /></div>
<svg width="200" height="200" >
   <circle id="bg" r="100" cx="100" cy="100"  fill="#665555"/>  
       
   <path id="p15"  stroke-dasharray="15.7,298.3"  d="M100,50A50,50 0 0 1 100,150A50,50 0 0 1 100,50" id="p1" fill="none" stroke="#9ACD32" stroke-width="100" >
  </path> 
   <text id="txt1" y="60%" x="50%"  text-anchor="middle" font-size="32px" fill="white">0</text>
</svg>   
    

【讨论】:

  • @stepheniok 我添加了一个在饼图中显示百分比的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多