如何用 CSS3 做环图
代码地址 css3 环图.zip 小程序组件
js
let getStyleByObj = (obj) => {
let result = "";
for (const key in obj) {
result += `${key}:${obj[key]};`;
}
return result;
};
function computedRate(accuracy) {
return Math.round((accuracy * 100).toFixed(2));
}
function computedColor(rate) {
rate = rate * 100;
var green = "#0FD36C",
blue = "#0089FF",
yellow = "#FFCB00",
red = "#FE5F69";
if (rate >= 80) {
return green;
}
if (rate >= 60 && rate < 80) {
return blue;
}
if (rate > 20 && rate < 60) {
return yellow;
}
if (rate <= 20) {
return red;
}
return blue;
}
Component({
options: {
addGlobalClass: true,
},
observers: {
percent: function(num) {
this.initVar().then(() => {
let rate = computedRate(num);
this.setData({
rate,
});
let color = computedColor(rate);
/* 超过边界 */
if (rate < 0) {
this.data.progress["border-color"] = this.data.bgColor;
this.data.before["border-color"] = this.data.bgColor;
this.data.after["border-color"] = this.data.bgColor;
}
if (rate > 100) {
this.data.progress["border-color"] = color;
this.data.before["border-color"] = color;
this.data.after["border-color"] = color;
}
if (rate > 50 && rate <= 100) {
let deg = (rate - 50) * 3.6;
this.data.after.transform = `rotate(${deg}deg)`;
this.data.after["border-color"] = color;
this.data.progress["border-color"] = color;
this.data.before["border-color"] = this.data.bgColor;
if (rate == 100) {
this.data.before["border-color"] = color;
}
}
if (rate >= 0 && rate <= 50) {
let deg = rate * 3.6;
this.data.progress.transform = `rotate(${deg}deg)`;
this.data.progress["border-color"] = this.data.bgColor;
this.data.before["border-color"] = this.data.bgColor;
this.data.after["border-color"] = color;
if (rate == 0) {
this.data.after["border-color"] = this.data.bgColor;
}
}
this.setData({
color,
});
this.init();
});
},
},
data: {
color: "",
rate: "0",
bgColor: "#EDEFF3",
chartStyle: "",
beforeStyle: "",
afterStyle: "",
progressStyle: "",
chart: {
width: "80px",
height: "80px",
float: "left",
position: "relative",
"text-align": "center",
},
before: {
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#ccc",
"border-radius": "50%",
"z-index": 1,
},
after: {
transform: "",
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#999",
"border-radius": "50%",
clip: "rect(0,auto,auto,40px)",
"z-index": 2,
},
progress: {
transform: "",
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#999",
"border-radius": "50%",
clip: "rect(0,auto,auto,40px)",
"z-index": 3,
},
},
properties: {
percent: {
type: Number,
value: 0,
},
},
methods: {
initVar() {
return new Promise((resolve, reject) => {
this.setData(
{
chart: {
width: "80px",
height: "80px",
float: "left",
position: "relative",
"text-align": "center",
},
before: {
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#ccc",
"border-radius": "50%",
"z-index": 1,
},
after: {
transform: "",
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#999",
"border-radius": "50%",
clip: "rect(0,auto,auto,40px)",
"z-index": 2,
},
progress: {
transform: "",
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
border: "6px solid",
"border-color": "#999",
"border-radius": "50%",
clip: "rect(0,auto,auto,40px)",
"z-index": 3,
},
},
() => {
resolve();
}
);
});
},
init() {
this.setData({
chartStyle: getStyleByObj(this.data.chart),
beforeStyle: getStyleByObj(this.data.before),
afterStyle: getStyleByObj(this.data.after),
progressStyle: getStyleByObj(this.data.progress),
});
},
},
});
wxml
<view style="corlor:red;{{chartStyle}}">
<view style="{{beforeStyle}}"></view>
<view style="{{progressStyle}}"></view>
<view class="component-rate-panel">
<view class="rate" style="color:{{color}};">{{rate}}%</view>
<view class="text">正确率</view>
</view>
<view style="{{afterStyle}}"></view>
</view>
wxss
.component-rate-panel {
width: 100%;
height: 100%;
position: absolute;
left: 0rpx;
top: 0rpx;
z-index: 2;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.component-rate-panel .rate {
font-family: PingFangSC-Semibold;
font-size: 35rpx;
color: #0089ff;
letter-spacing: 0.16rpx;
position: relative;
left: 3rpx;
}
.component-rate-panel .text {
font-family: PingFangSC-Regular;
font-size: 18rpx;
color: #9ea7b7;
margin-top: 1rpx;
}
json
{
"component": true
}
Canvas 画一个半圆
function drawScreen(myCanvas, r, lw, lr, rr, g) {
// x,y => 圆心坐标点
// r => 圆弧半径
var arc = {
x: myCanvas.width / 2,
y: myCanvas.height / 2 + 16,
r: (myCanvas.height - r) / 2
}
var ctx = myCanvas.getContext('2d')
ctx.save()
ctx.lineWidth = lw
if (g) {
//计算渐变起始坐标
let L = Math.sqrt(Math.pow(arc.r, 2) / 2)
let gx0 = arc.x - L
let gy0 = arc.y + L
/* 指定渐变区域 */
var grad = ctx.createLinearGradient(
arc.x - L,
arc.y + L,
arc.x - L,
arc.y
)
grad.addColorStop(1, '#FEE891')
grad.addColorStop(0, '#FEB832')
ctx.strokeStyle = grad
} else {
ctx.strokeStyle = '#F2F3F8'
}
// 顺时针旋转
ctx.beginPath()
ctx.arc(arc.x, arc.y, arc.r, getRads(lr), getRads(rr))
ctx.stroke()
}
function getRads(degrees) {
return Math.PI * degrees / 180
}
function getDegrees(rads) {
return rads * 180 / Math.PI
}
export default {
mounted: () => {
//获取根元素字体大小计算rem
let fontSize = document.documentElement.style.fontSize
CONST.fontSize = parseInt(fontSize.substring(0, fontSize.length - 2))
CONST.width = document.body.clientWidth
CONST.widthRem = CONST.width / CONST.fontSize
drawScreen(document.getElementById('circle'), 0, 6, 135, 45) //绘制外层灰色
drawScreen(document.getElementById('circle'), 36, 1.5, 132, 48) //绘制内层灰色
drawScreen(document.getElementById('circle'), 0, 6, 135, 200, true) //绘制渐变
}
}
flex 横向 margin-right 最后一个不生效
<div class="relation-reason-item-panel">
<div class="relation-reason-item" v-for="">
<div class="top">
<img :src="$_img + 'page_book_detail_v2_icon_question.png'" alt class="icon" />
<div class="question-title"></div>
</div>
<div class="nums">234个方案 · 超2345人已阅读过</div>
<img :src="$_img + 'page_book_detail_v2_bg_question.png'" alt class="bg" />
</div>
<div style="width:0.1vw;flex-shrink:0"></div>
</div>
在最后加一个 div shrink:0 width 有一点就好了