刚看到设计稿的时候第一时间想到的就是用canvas
来做这个仪表盘,虽然本人的画布用的不是很好但还可以写一写😀。话不多说直接上代码。最后有纯css
方法
<!--wxml-->
<canvas canvas-id="circle" class="circle" >
// js
data: {
canvasWidth: 285, // 画布宽度
canvasHeight: 285, // 画布高度
value: 60, // 当前得分
},
/*
* 绘制仪表盘
*/
showCanvasRing() {
var that = this;
var ctx = wx.createCanvasContext("circle");
ctx.clearRect(0, 0, that.data.canvasWidth, that.data.canvasHeight); // 清除画布
var circle_r = that.data.canvasWidth / 2; //画布的一半,用来找中心点和半径
var scoreText = that.data.value>=100?100:that.data.value; // 当前得分 最多100分
var descript = '良好'; // 当前描述
var date = formatTime(new Date(),'MM-DD'); // 当前日期
// 圆弧起点
var startAngle = 0.8 * Math.PI;
var endAngle = 2.2 * Math.PI;
//定义起始点
ctx.translate(that.data.canvasWidth / 2, that.data.canvasHeight / 2);
// 画圆背景
ctx.beginPath();
ctx.setStrokeStyle("#6bb7b9");
ctx.fillStyle="#6bb7b9";
ctx.setLineCap("round");
ctx.arc(0, 0, circle_r,2*Math.PI);
ctx.fill()
ctx.stroke();
ctx.closePath();
// 白半边圆弧
ctx.beginPath();
ctx.setStrokeStyle("#FFFFFF");
ctx.setLineWidth(10);
ctx.setLineCap("round");
ctx.arc(0, 0, circle_r - 20, startAngle, endAngle, false);
ctx.stroke();
ctx.closePath();
// 刻度
for (let i = 0; i <= 10; i++) {
let angle = startAngle + (endAngle - startAngle - 0.1) * (i * 10) / 100;
if (angle > Math.PI * 2) {
angle = angle - Math.PI * 2
}
const point = that.getPoint(0, 0, circle_r - 44, angle);
const PI_3_2 = Math.PI * 1.5;
const PI_1_2 = Math.PI * 0.5;
ctx.save()
ctx.setFillStyle("#fff");
ctx.setFontSize(13);
ctx.translate(point.x, point.y)
const rotateDegrees = angle >= PI_3_2 ? (angle - PI_3_2) : (angle + PI_1_2);
ctx.rotate(rotateDegrees)
ctx.fillText(i * 10, 0, 0)
ctx.restore()
}
// 当前得分内圆弧
ctx.beginPath();
ctx.setStrokeStyle("#FFA64D");
ctx.setLineWidth(10);
ctx.setLineCap("round");
ctx.arc(0, 0, circle_r - 20, startAngle, startAngle + (endAngle - startAngle) * scoreText / 100, false);
ctx.stroke();
ctx.closePath();
// 分数
ctx.setTextAlign("center"); // 字体位置
ctx.setFillStyle("#fff");
ctx.font = "900 50px Arial"
ctx.fillText(scoreText, 0, -20);
// 描述
ctx.setTextAlign("center"); // 字体位置
ctx.font = "400 15px Arial"
ctx.fillText(descript, 0, 15);
// 日期
ctx.setTextAlign("center");
ctx.setLineWidth(8);
ctx.setFontSize(14);
ctx.fillText(date + ' 更新', 0, 35);
// 绘图
ctx.draw();
},
getPoint: function (x, y, r, angle) {
const x1 = x + r * Math.cos(angle);
const y1 = y + r * Math.sin(angle);
return {
x: x1,
y: y1
}
},
到此仪表盘就画完了,最后需求有变动需要再仪表盘上加文本,众所周知canvas
在小程序中的层级很高。但是官方说可以使用cover-view | cover-image
<canvas canvas-id="circle" class="circle" >
<cover-view class="lowScore" wx-if="{{showView}}">
目前信用分过低
</cover-view>
</canvas>
经过验证cover-view
可以做到在canvas
上悬浮,但是不能满足所有需求;
比如要悬浮scroll-view
,总不能把内容全部用画布来写吧 ~ ~。也有人说可以将绘画完成后的canvas
转成图片进行显示wx.canvasToTempFilePath
。我同样也试过但是会报错:canvasToTempFilePath:fail fail canvas is empty
,怎么解决试了好半天,由于项目着急也没用太多时间研究了。所有最后我决定使用最原始的方法来实现。来看代码吧 ↓ ↓
<!--wxml-->
<view class="dashboard">
<view class="dashboard-arc">
<view class="dashboard-scale">
<view wx:for="{{[0,10,20,30,40,50,60,70,80,90,100]}}" wx:key="item">{{item}}</view>
</view>
<view class="dashboard-arc-active" style="background: conic-gradient(#FFA64D 0, #FFA64D {{(value*0.75)}}%, transparent 0, transparent);">
<view class="dashboard-arc-active-end" style="transform: translateX(-50%) rotate({{(value/100)*270}}deg);"></view>
</view>
</view>
<view class="dashboard-content">
<view class="dashboard-content-title">{{value}}</view>
<view class="dashboard-content-text">{{state}}</view>
<view class="dashboard-content-desc">{{tool.formatTime(date,'MM-DD')}} 更新</view>
</view>
<view class="lowScore" wx-if="{{showView}}">目前信用分过低</view>
...要悬浮的内容
</view>
/* 仪表盘 */
.dashboard {
width: 750rpx;
height: 600rpx;
background: rgba(70, 165, 168, 1);
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.1);
text-align: center;
position: relative;
}
.dashboard::before{
content: '';
width: 570rpx;
height: 570rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #6bb7b9;
border-radius: 50%;
}
.dashboard-arc{
width: 520rpx;
height: 520rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform: translate(-50%, -50%) rotate(-135deg);
border-radius: 50%;
background: conic-gradient(#fff 0, #fff 75%, transparent 0, transparent);
}
.dashboard-arc::before,
.dashboard-arc::after{
content: "";
position: absolute;
width: 20rpx;
height: 20rpx;
border-radius: 50%;
background: #fff;
}
.dashboard-arc::before{
left: 50%;
top: 0;
background-color: #FFA64D;
transform: translateX(-50%);
}
.dashboard-arc::after{
left: 0;
top: 50%;
transform: translateY(-50%);
}
.dashboard-arc-active{
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
top: 0;
left: 0;
}
.dashboard-arc-active-end{
position: absolute;
width: 20rpx;
height:100%;
top: 0;
left: 50%;
z-index: 1;
}
.dashboard-arc-active-end::before{
content: '';
width: 20rpx;
height: 20rpx;
position: absolute;
top: 0;
left: 0;
background: #FFA64D;
border-radius: 50%;
}
.dashboard-scale{
background-color: #6bb7b9;
width: 480rpx;
height: 480rpx;
border-radius: 50%;
position: relative;
top: 50%;
left: 50%;
z-index: 99;
font-size: 20rpx;
transform: translate(-50%, -50%);
color: #fff;
}
.dashboard-scale>view{
position: absolute;
top: 50%;
height:calc(100% - 10rpx);
left: 50%;
transform: translate(-50%,-50%);
}
.dashboard-scale>view:nth-child(2){
transform:translate(-50%,-50%)rotate(27deg);
}
.dashboard-scale>view:nth-child(3){
transform:translate(-50%,-50%)rotate(54deg);
}
.dashboard-scale>view:nth-child(4){
transform:translate(-50%,-50%)rotate(81deg);
}
.dashboard-scale>view:nth-child(5){
transform:translate(-50%,-50%)rotate(108deg);
}
.dashboard-scale>view:nth-child(6){
transform:translate(-50%,-50%)rotate(135deg);
}
.dashboard-scale>view:nth-child(7){
transform:translate(-50%,-50%)rotate(162deg);
}
.dashboard-scale>view:nth-child(8){
transform:translate(-50%,-50%)rotate(189deg);
}
.dashboard-scale>view:nth-child(9){
transform:translate(-50%,-50%)rotate(216deg);
}
.dashboard-scale>view:nth-child(10){
transform:translate(-50%,-50%)rotate(243deg);
}
.dashboard-scale>view:nth-child(11){
transform:translate(-50%,-50%)rotate(270deg);
}
.dashboard-content{
position: absolute;
width: 300rpx;
height: 300rpx;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
border-radius: 50%;
padding: 20rpx;
}
.dashboard-content-title{
font-size: 115rpx;
font-weight: 900;
}
.dashboard-content-text{
font-size: 25rpx;
}
.dashboard-content-desc{
font-size: 20rpx;
}
以上就是所有代码了,觉得对你有用的话就点个赞吧 !
最后给大家推荐一个在线题库
小程序包含了阿里云认证、腾讯云认证、华为云认证、思科认证、锐捷认证、瓴羊认证、红帽认证、软考、IT认证等等