效果图:

//做环形图的本质是 radius: ['内半径', '外半径'] 内半径!=0
//画渐变色的原理是:data里面可以设置itemStyle
let angle = 0; //角度,用来做简单的动画效果的
let timerId;
const legend = {
show: false,
};
const tooltip = {
show: false,
};
const colors = ['#00fcff', '#4386FA','#4FADFD','#0CD3DB','#646CF9'];
const innerRingColor = {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [0,.3,.6,.8,1].map((offset,index)=>({offset,color:colors[index]})),
global: false, // 缺省为 false
};
var trafficWay = [
{
name: 'Ⅰ类',
value: 10,
},
{
name: 'Ⅱ类',
value: 20,
},
{
name: 'Ⅲ类',
value: 20,
},
{
name: 'Ⅳ类',
value: 20,
},
];
var dataArr = [];
for (var i = 0; i < 4; i++) {
if (i % 2 === 0) {
dataArr.push({
name: (i + 1).toString(),
value: 25,
itemStyle: {
normal: {
color: "#F1B35E",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)"
}
}
}, {
value: 4,
name: '',
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(0, 0, 0, 0)',
borderWidth: 0,
},
},
})
} else {
dataArr.push({
name: (i + 1).toString(),
value: 20,
itemStyle: {
normal: {
color: "#F1B35E",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)"
}
}
}, {
value: 4,
name: '',
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(0, 0, 0, 0)',
borderWidth: 0,
},
},
})
}
}
var data = [];
var color = ['#56FFD7', '#6DA7FF', '#2B64FF', '#68FF83', '#8792FF', '#F6FD6A'];
for (var i = 0; i < trafficWay.length; i++) {
data.push(
{
value: trafficWay[i].value,
name: trafficWay[i].name,
itemStyle: {
normal: {
borderWidth: 5,
shadowBlur: 2,
borderColor: color[i],
shadowColor: color[i],
},
},
},
{
value: 2,
name: '',
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(0, 0, 0, 0)',
borderWidth: 0,
},
},
}
);
}
option = {
color:colors,
tooltip,
legend,
series: [
{
name: '',
type: 'pie',
clockWise: false,
radius: [119, 124],
hoverAnimation: false,
labelLine: {
normal: {
length: 10,
length2: 14,
}
},
label: {
show: false,
position: 'outer',
alignTo: 'labelLine',
// ·圆点
backgroundColor: 'auto',
height: 0,
width: 0,
lineHeight: 0,
distanceToLabelLine: 0,
borderRadius: 2.5,
padding: [2.5, -2.5, 2.5, -2.5],
formatter: function (params) {
if (params.name !== '') {
return `{a|${params.name}:}{b|${params.value}个}`;
} else {
return '';
}
},
rich: {
a: {
padding: [0, 0, 0, 10],
color: '#fff'
},
b: {
padding: [0, 10, 0, 0],
color: '#fff'
},
}
},
data: data,
},
{
type: 'pie',
clockWise: false, //顺时加载
hoverAnimation: false, //鼠标移入变大
center: ['50%', '50%'],
radius: ['30%', '30%'],
label:{
show:false
},
data: [{
value: 2,
name: '',
itemStyle: {
normal: {
borderWidth: 2,
borderColor: '#61bad3'
}
}
}]
},
/* {
name: '',
type: 'pie',
center: ['50%', '50%'], //圆心的位置
radius: ['32%', '35%'], //环形图的本质就在这里 [内半径!=0,外半径] 外半径越大,圆越大
avoidLabelOverlap: false, //做同心圆用到
clockwise: false, //顺时针排列
startAngle: 90, //起始角度 影响不大
label: {
show: true, //false不显示饼图上的标签
position: 'center', //inside(在饼图上显示),outside(默认就会出现引导线) center
formatter: '{d}%',
fontSize: 50,
fontWeight: 'bold',
},
data: [
{ value: value, name: '完成', itemStyle: { color: innerRingColor, opacity: 1 } },
{ value: 100 - value, name: '未完成', itemStyle: { color: '#282c40' } },
].sort((a, b) => b.value - a.value), //数组从大到小排序
emphasis: {
scale: false,
},
}, */
/* {
name: '',
type: 'pie',
center: ['50%', '50%'], //圆心的位置
radius: ['40%', '50%'], //环形图的本质就在这里 [内半径!=0,外半径] 外半径越大,圆越大
avoidLabelOverlap: false, //做同心圆用到
clockwise: false, //顺时针排列
startAngle: 90, //起始角度 影响不大
label: {
show: false, //false不显示饼图上的标签
},
data: [
{ value: value, name: '完成', itemStyle: { color: innerRingColor, opacity: 1 }},
{ value: 100 - value, name: '未完成', itemStyle: { color: '#282c40' } },
].sort((a, b) => b.value - a.value), //数组从大到小排序
emphasis: {
scale: false,
},
}, */
//colors[0]line
{
name: 'ring5',
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
return {
type: 'arc',
shape: {
cx: api.getWidth() / 2,
cy: api.getHeight() / 2,
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
startAngle: ((0 + angle) * Math.PI) / 180,
endAngle: ((90 + angle) * Math.PI) / 180,
},
style: {
stroke: colors[0],
fill: 'transparent',
lineWidth: 1.5,
},
silent: true,
};
},
data: [0],
},
{
name: 'ring5', // //colors[0]dot
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
let x0 = api.getWidth() / 2;
let y0 = api.getHeight() / 2;
let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6;
let point = getCirlPoint(x0, y0, r, 90 + angle);
return {
type: 'circle',
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[0],
fill: colors[0],
},
silent: true,
};
},
data: [0],
},
// 蓝色
{
name: 'ring5',
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
return {
type: 'arc',
shape: {
cx: api.getWidth() / 2,
cy: api.getHeight() / 2,
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
startAngle: ((180 + angle) * Math.PI) / 180,
endAngle: ((270 + angle) * Math.PI) / 180,
},
style: {
stroke: colors[1],
fill: 'transparent',
lineWidth: 1.5,
},
silent: true,
};
},
data: [0],
},
{
name: 'ring5', // 蓝色
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
let x0 = api.getWidth() / 2;
let y0 = api.getHeight() / 2;
let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6;
let point = getCirlPoint(x0, y0, r, 180 + angle);
return {
type: 'circle',
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[1], //绿
fill: colors[1],
},
silent: true,
};
},
data: [0],
},
{
name: 'ring5',
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
return {
type: 'arc',
shape: {
cx: api.getWidth() / 2,
cy: api.getHeight() / 2,
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
startAngle: ((270 + -angle) * Math.PI) / 180,
endAngle: ((40 + -angle) * Math.PI) / 180,
},
style: {
stroke: colors[2],
fill: 'transparent',
lineWidth: 1.5,
},
silent: true,
};
},
data: [0],
},
// 橘色
{
name: 'ring5',
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
return {
type: 'arc',
shape: {
cx: api.getWidth() / 2,
cy: api.getHeight() / 2,
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
startAngle: ((90 + -angle) * Math.PI) / 180,
endAngle: ((220 + -angle) * Math.PI) / 180,
},
style: {
stroke: colors[2],
fill: 'transparent',
lineWidth: 1.5,
},
silent: true,
};
},
data: [0],
},
{
name: 'ring5',
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
let x0 = api.getWidth() / 2;
let y0 = api.getHeight() / 2;
let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65;
let point = getCirlPoint(x0, y0, r, 90 + -angle);
return {
type: 'circle',
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[3], //粉
fill: colors[3],
},
silent: true,
};
},
data: [0],
},
{
name: 'ring5', //绿点
type: 'custom',
coordinateSystem: 'none',
renderItem: function (params, api) {
let x0 = api.getWidth() / 2;
let y0 = api.getHeight() / 2;
let r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65;
let point = getCirlPoint(x0, y0, r, 270 + -angle);
return {
type: 'circle',
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[3], //绿
fill: colors[3],
},
silent: true,
};
},
data: [0],
},
],
};
//获取圆上面某点的坐标(x0,y0表示坐标,r半径,angle角度)
function getCirlPoint(x0, y0, r, angle) {
let x1 = x0 + r * Math.cos((angle * Math.PI) / 180);
let y1 = y0 + r * Math.sin((angle * Math.PI) / 180);
return {
x: x1,
y: y1,
};
}
function draw() {
angle = angle + 3;
myChart.setOption(option, true);
//window.requestAnimationFrame(draw);
}
draw();
setTimeout(function () {
if (timerId) {
clearInterval(timerId);
}
timerId = setInterval(function () {
//用setInterval做动画感觉有问题
draw();
}, 100);
}, 500);
更完善的版本
效果图:

safeEchart() {
//做环形图的本质是 radius: ['内半径', '外半径'] 内半径!=0
//画渐变色的原理是:data里面可以设置itemStyle
let angle = 0; //角度,用来做简单的动画效果的
let widthCustom = 700;
let timerId;
const tooltip = {
show: false,
};
const colors = [
"#00fcff",
"#00c1ff",
"#ef9c00",
"#00ff84",
];
const innerRingColor = {
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [0, 0.3, 0.6, 0.8, 1].map(
(offset, index) => ({
offset,
color: colors[index],
})
),
global: false, // 缺省为 false
};
var trafficWay = [
{
name: "风险区",
value: 1492,
},
{
name: "两重点一重大",
value: 1492,
},
{
name: "危化品",
value: 1492,
},
{
name: "固定动火点",
value: 1492,
},
];
let legend = [];
let item = {
top: 100,
right: 600,
itemWidth: 40,
itemHeight: 40,
textStyle: {
fontSize: 16,
color: "rgba(255,255,255,1)",
rich: {
name: {
fontSize: 38,
padding: [0, 0, 100, 0], //上,右,下,左
color: "",
},
value: {
fontSize: 60,
fontFamily: "PangMenZhengDao",
padding: [-8, -50],
},
unit: {
fontSize: 36,
verticalAlign: "bottom",
padding: [0, 0, 0, 50],
color: "#fff",
},
},
},
formatter: function(params) {
// console.log(params)
// return [`{name|${'风险区'}}`, `{value|${123124}}`].join('\n')
},
data: [""],
};
const deepCopy = (newObj, oldObj) => {
for (let k in oldObj) {
var item = oldObj[k];
if (item instanceof Array) {
newObj[k] = [];
deepCopy(newObj[k], item);
} else if (item instanceof Object) {
newObj[k] = {};
deepCopy(newObj[k], item);
} else {
newObj[k] = item;
}
}
};
for (let i = 0; i < trafficWay.length; i++) {
if (i == 0) {
let item1 = {};
deepCopy(item1, item);
item1.right = 500;
item1.textStyle.rich.name.color = "#00fcff";
item1.formatter = function() {
return [
`{name|${trafficWay[i].name}}`,
``,
``,
``,
`{value|${trafficWay[i].value}}{unit|个}`,
].join("\n");
};
item1.data = [`${trafficWay[i].name}`];
legend[i] = item1;
} else if (i == 1) {
let item1 = {};
deepCopy(item1, item);
item1.right = 50;
item1.textStyle.rich.name.color = "#00c1ff";
item1.formatter = function() {
return [
`{name|${trafficWay[i].name}}`,
``,
``,
``,
`{value|${trafficWay[i].value}}{unit|个}`,
].join("\n");
};
item1.data = [`${trafficWay[i].name}`];
legend[i] = item1;
} else if (i == 2) {
let item1 = {};
for (var j in item) {
item1[j] = item[j];
}
item1.right = 500;
item1.top = 400;
item1.textStyle.rich.name.color = "#ef9c00";
item1.formatter = function() {
return [
`{name|${trafficWay[i].name}}`,
``,
``,
``,
`{value|${trafficWay[i].value}}{unit|个}`,
].join("\n");
};
item1.data = [`${trafficWay[i].name}`];
legend[i] = item1;
} else if (i == 3) {
let item1 = {};
deepCopy(item1, item);
item1.right = 100;
item1.top = 400;
item1.textStyle.rich.name.color = "#00ff84";
item1.formatter = function() {
return [
`{name|${trafficWay[i].name}}`,
``,
``,
``,
`{value|${trafficWay[i].value}}{unit|个}`,
].join("\n");
};
item1.data = [`${trafficWay[i].name}`];
legend[i] = item1;
}
}
var dataArr = [];
for (var i = 0; i < 4; i++) {
if (i % 2 === 0) {
dataArr.push(
{
name: (i + 1).toString(),
value: 15,
itemStyle: {
normal: {
color: "#F1B35E",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)",
},
},
},
{
value: 1,
name: "",
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: "rgba(0, 0, 0, 0)",
borderColor: "rgba(0, 0, 0, 0)",
borderWidth: 0,
},
},
}
);
} else {
dataArr.push(
{
name: (i + 1).toString(),
value: 20,
itemStyle: {
normal: {
color: "#F1B35E",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)",
},
},
},
{
value: 4,
name: "",
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: "rgba(0, 0, 0, 0)",
borderColor: "rgba(0, 0, 0, 0)",
borderWidth: 0,
},
},
}
);
}
}
var data = [];
var color = [
"#00fcff",
"#00c1ff",
"#ef9c00",
"#00ff84",
];
for (var i = 0; i < trafficWay.length; i++) {
data.push(
{
value: trafficWay[i].value,
name: trafficWay[i].name,
itemStyle: {
normal: {
borderWidth: 5,
shadowBlur: 2,
borderColor: color[i],
shadowColor: color[i],
},
},
},
{
value: 200,
name: "",
itemStyle: {
normal: {
label: {
show: false,
},
labelLine: {
show: false,
},
color: "rgba(0, 0, 0, 0)",
borderColor: "rgba(0, 0, 0, 0)",
borderWidth: 0,
},
},
}
);
}
let option = {
color: colors,
tooltip,
legend,
title: [
{
text: "5236", //主标题
left: "20%", //标题的位置 默认是left,其余还有center、right属性
top: "40%",
textStyle: {
color: "#ef9c00",
fontSize: 70,
fontWeight: "bold",
fontFamily: "PangMenZhengDao",
},
},
{
subtext: "总数", //副标题
// itemGap: 6, //主副标题间距
left: "24%", //标题的位置 默认是left,其余还有center、right属性
top: "50%",
subtextStyle: {
color: "#FFFFFF",
fontSize: 38,
fontWeight: "600",
letterSpacing: 10,
textAlign: "center",
},
},
],
series: [
{
name: "",
type: "pie",
clockWise: false,
center: ["27%", "50%"],
radius: [149, 164],
hoverAnimation: false,
labelLine: {
normal: {
length: 10,
length2: 14,
},
},
label: {
show: false,
position: "outer",
alignTo: "labelLine",
// ·圆点
backgroundColor: "auto",
height: 0,
width: 0,
lineHeight: 0,
distanceToLabelLine: 0,
borderRadius: 2.5,
padding: [2.5, -2.5, 2.5, -2.5],
formatter: function(params) {
if (params.name !== "") {
return `{a|${params.name}:}{b|${params.value}个}`;
} else {
return "";
}
},
rich: {
a: {
padding: [0, 0, 0, 10],
color: "#fff",
},
b: {
padding: [0, 10, 0, 0],
color: "#fff",
},
},
},
data: data,
},
{
type: "pie",
clockWise: false, //顺时加载
hoverAnimation: false, //鼠标移入变大
center: ["27%", "50%"],
radius: ["32%", "32%"],
label: {
show: false,
},
data: [
{
value: 2,
name: "",
itemStyle: {
normal: {
borderWidth: 2,
borderColor: "#61bad3",
},
},
},
],
},
{
name: "ring5",
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
return {
type: "arc",
shape: {
cx: widthCustom / 2,
cy: api.getHeight() / 2,
r:
(Math.min(
api.getWidth(),
api.getHeight()
) /
2) *
0.6,
startAngle: ((0 + angle) * Math.PI) / 180,
endAngle: ((90 + angle) * Math.PI) / 180,
},
style: {
stroke: colors[0],
fill: "transparent",
lineWidth: 4.5,
},
silent: true,
};
},
data: [0],
},
{
name: "ring5", // //colors[0]dot
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
let x0 = widthCustom / 2;
let y0 = api.getHeight() / 2;
let r =
(Math.min(api.getWidth(), api.getHeight()) /
2) *
0.6;
let point = getCirlPoint(
x0,
y0,
r,
90 + angle
);
return {
type: "circle",
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[0],
fill: colors[0],
},
silent: true,
};
},
data: [0],
},
// 蓝色
{
name: "ring5",
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
return {
type: "arc",
shape: {
cx: widthCustom / 2,
cy: api.getHeight() / 2,
r:
(Math.min(
api.getWidth(),
api.getHeight()
) /
2) *
0.6,
startAngle:
((180 + angle) * Math.PI) / 180,
endAngle: ((270 + angle) * Math.PI) / 180,
},
style: {
stroke: colors[1],
fill: "transparent",
lineWidth: 4.5,
},
silent: true,
};
},
data: [0],
},
{
name: "ring5", // 蓝色
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
let x0 = widthCustom / 2;
let y0 = api.getHeight() / 2;
let r =
(Math.min(api.getWidth(), api.getHeight()) /
2) *
0.6;
let point = getCirlPoint(
x0,
y0,
r,
180 + angle
);
return {
type: "circle",
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[1], //绿
fill: colors[1],
},
silent: true,
};
},
data: [0],
},
{
name: "ring5",
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
return {
type: "arc",
shape: {
cx: widthCustom / 2,
cy: api.getHeight() / 2,
r:
(Math.min(
api.getWidth(),
api.getHeight()
) /
2) *
0.65,
startAngle:
((270 + -angle) * Math.PI) / 180,
endAngle: ((40 + -angle) * Math.PI) / 180,
},
style: {
stroke: colors[2],
fill: "transparent",
lineWidth: 4.5,
},
silent: true,
};
},
data: [0],
},
// 橘色
{
name: "ring5",
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
return {
type: "arc",
shape: {
cx: widthCustom / 2,
cy: api.getHeight() / 2,
r:
(Math.min(
api.getWidth(),
api.getHeight()
) /
2) *
0.65,
startAngle:
((90 + -angle) * Math.PI) / 180,
endAngle:
((220 + -angle) * Math.PI) / 180,
},
style: {
stroke: colors[2],
fill: "transparent",
lineWidth: 4.5,
},
silent: true,
};
},
data: [0],
},
{
name: "ring5",
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
let x0 = widthCustom / 2;
let y0 = api.getHeight() / 2;
let r =
(Math.min(api.getWidth(), api.getHeight()) /
2) *
0.65;
let point = getCirlPoint(
x0,
y0,
r,
90 + -angle
);
return {
type: "circle",
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[3], //粉
fill: colors[3],
},
silent: true,
};
},
data: [0],
},
{
name: "ring5", //绿点
type: "custom",
coordinateSystem: "none",
renderItem: function(params, api) {
let x0 = widthCustom / 2;
let y0 = api.getHeight() / 2;
let r =
(Math.min(api.getWidth(), api.getHeight()) /
2) *
0.65;
let point = getCirlPoint(
x0,
y0,
r,
270 + -angle
);
return {
type: "circle",
shape: {
cx: point.x,
cy: point.y,
r: 4,
},
style: {
stroke: colors[3], //绿
fill: colors[3],
},
silent: true,
};
},
data: [0],
},
],
};
//获取圆上面某点的坐标(x0,y0表示坐标,r半径,angle角度)
let getCirlPoint = (x0, y0, r, angle) => {
let x1 = x0 + r * Math.cos((angle * Math.PI) / 180);
let y1 = y0 + r * Math.sin((angle * Math.PI) / 180);
return {
x: x1,
y: y1,
};
};
let myChart = this.$echarts.init(
document.getElementById("safeId")
);
let draw = () => {
angle = angle + 3;
myChart.setOption(option, true);
//window.requestAnimationFrame(draw);
};
draw();
setTimeout(function() {
if (timerId) {
clearInterval(timerId);
}
timerId = setInterval(function() {
//用setInterval做动画感觉有问题
draw();
}, 100);
}, 500);
},