vue+css实现圆环渐变仪表盘
vue+css实现圆环+渐变色+仪表盘+进度条
·
整体效果
主要原理
-
渐变圆环
-
设置如下css代码可实现出环形渐变效果
.box{ background:conic-gradient(from 0deg at 50% 50%,#eee 0deg,yelllow 180deg,red 360deg) }
效果图
-
添加圆角以及内部圆形居中遮挡即可实现圆环效果
效果图
-
-
仪表盘效果
添加若干个环绕圆点旋转的元素,组成仪表盘,融合背景色将底色圆环覆盖掉,就得到了仪表盘效果。
-
div结构
<div class="scale"> <div class="s-item" v-for="item in 72" :key="'item-' + item" > </div> </div>
-
scss
.scale { border-radius: 50%; width: 100%; height: 100%; position: absolute; .s-item { position: absolute; width: 1px; height: 2px; background-color: #fff; left:50%; top: 0px; transform-origin: 0 24px; } @for $i from 0 through 72 { .s-item:nth-child(#{$i + 1}) { transform: rotate($i * 5deg); } } }
形式图 效果图
-
全部代码
<template>
<div
class="gauge"
:style="{
width: diameter + 'px',
height: diameter + 'px',
background: bgColor,
}"
>
<div class="cricle" ref="cricle">
<!-- 色块圈 -->
<div
class="s-color"
:style="
follow
? {
background: `conic-gradient(from 0deg at 50% 50%,${
rampColor[0]
} 0deg,${rampColor[1]} ${value / 2}deg,${
rampColor[2]
} ${value}deg,${defaultColor} ${value}deg)`,
}
: {
background: `conic-gradient(from 0deg at 50% 50%,${rampColor[0]} 0deg,${rampColor[1]} 50%,${rampColor[2]}`,
}
"
>
<div
class="follow"
v-if="!follow"
:style="{
background: `conic-gradient(from 0deg at 50% 50%,transparent 0deg,transparent ${value}deg,${defaultColor} ${value}deg)`,
}"
></div>
<div
class="mask"
:style="{
width: `calc(100% - ${dotHeight}px *2)`,
height: `calc(100% - ${dotHeight}px *2)`,
background: bgColor,
}"
></div>
</div>
<!-- 拖动按钮 -->
<div
class="slider"
:style="{
transform: `rotate(${value}deg)`,
width: sliderDiameter + 'px',
height: `calc(50% - ${dotHeight / 2}px + ${sliderDiameter / 2}px)`,
left: `calc(50% - ${sliderDiameter / 2}px)`,
top: `calc((${sliderDiameter / 2}px - ${dotHeight / 2}px) *-1)`,
}"
>
<div
class="btn"
ref="slider"
:style="{
width: sliderDiameter + 'px',
height: sliderDiameter + 'px',
background: sliderColor,
}"
></div>
</div>
<!-- 仪表盘 -->
<div class="bar scale">
<div
class="s-item"
v-for="item in dotCount"
:key="'item-' + item"
:style="{
'transform-origin': `2px calc(${diameter}px/2 + 1px)`,
width: dotWidth + 'px',
height: diameter / 2 + 'px',
transform: `rotate(${(item * 360) / dotCount}deg)`,
background: bgColor,
}"
></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "gauge",
/** 组件参数 */
props: {
/** 默认值 */
default: {
type: Number,
default: 0,
},
/** 直径 */
diameter: {
type: Number,
default: 200,
},
/** 点间隔 */
dotWidth: {
type: Number,
default: 4,
},
/** 点高度 */
dotHeight: {
type: Number,
default: 8,
},
/** 滑块直径 */
sliderDiameter: {
type: Number,
default: 20,
},
/** 滑块颜色 */
sliderColor: {
type: String,
default: "red",
},
/** 点数量 */
dotCount: {
type: Number,
default: 72,
},
/** 渐变色 */
rampColor: {
type: Array,
default: function () {
return ["#ddd", "#faba2a", "#f24c4f"];
},
},
/** 环形默认颜色 */
defaultColor: {
type: String,
default: "#ddd",
},
/** 背景颜色 */
bgColor: {
type: String,
default: "#fff",
},
/** 渐变跟随 */
follow: {
type: Boolean,
default: true,
},
},
data() {
return {
value: 0,
};
},
methods: {
/** ## 组件方法 */
/** 获取进度 */
getValue(){
return this.value/360;
}
},
created() {
this.value = this.default;
},
mounted() {
/** 滑块滑动功能 */
this.$refs.slider.onmousedown = (e) => {
const cricle = this.$refs.cricle;
/** 获取位置(坐标轴原点) */
let client = cricle.getBoundingClientRect();
let x0 = client.x + cricle.offsetWidth / 2;
let y0 = client.y + cricle.offsetHeight / 2;
/** 阻止默认事件 */
let ev = e || window.event;
ev.preventDefault ? ev.preventDefault() : (ev.returnValue = false);
/** 鼠标移动 */
document.onmousemove = (el) => {
let move = el ? el : window.event;
/** 鼠标位置 */
let x = move.x - x0;
let y = y0 - move.y;
/** 计算角度 */
let deg = (Math.atan(y / x) / 2 / Math.PI) * 360;
if (x >= 0) {
if (this.value >= 270) {
/** 象限跳跃优化 */
this.value = 360;
} else {
this.value = 90 - deg;
}
} else {
if (this.value <= 90) {
this.value = 0;
} else {
this.value = 270 - deg;
}
}
};
/** 鼠标松开 */
document.onmouseup = () => {
/** 取消订阅鼠标移动事件 */
document.onmousemove = null;
document.onmouseup = null;
};
};
},
};
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
position: absolute;
}
.gauge {
padding: 5px;
//background-color: white;
position: relative;
.cricle {
width: calc(100% - 10px);
height: calc(100% - 10px);
position: absolute;
left: 50%;
top: 50%;
transform: translateY(-50%) translate(-50%);
.slider {
//background-color: pink;
width: 20px;
height: calc(50% + 6px);
position: absolute;
z-index: 10;
overflow: hidden;
transform-origin: 50% 100%;
top: -6px;
transform: rotate(140deg);
left: calc(50% - 10px);
.btn {
position: absolute;
cursor: pointer;
top: 0px;
width: 20px;
height: 20px;
// background-color: red;
border-radius: 50%;
}
}
.s-color {
z-index: 5; //5
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
.follow{
@extend .box;
// position: absolute;
// width: calc(100% + 2px );
// height: calc(100% + 2px);
left:50%;
top:50%;
transform: translate(-50%,-50%);
z-index: 6;
border-radius: 50%;
}
.mask {
content: "";
display: block;
position: absolute;
//background-color: #fff;
z-index: 9;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
}
.bar {
transform: rotate(0deg);
transform-origin: 0 100px;
}
.scale {
border-radius: 50%;
width: calc(100% + 2px);
height: calc(100% + 2px);
position: absolute;
z-index: 9;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.s-item {
position: absolute;
//background-color: #fff;
left: calc(50% - 2px);
top: 0px;
}
// @for $i from 0 through 72 {
// .s-item:nth-child(#{$i + 1}) {
// transform: rotate($i * 5deg);
// }
// }
}
}
}
</style>
更多推荐
已为社区贡献1条内容
所有评论(0)