|
@@ -1,252 +1,255 @@
|
|
<!-- 五维雷达图 -->
|
|
<!-- 五维雷达图 -->
|
|
<template>
|
|
<template>
|
|
- <div :id="id" :class="className" :style="{ height, width }" />
|
|
|
|
|
|
+ <div :id="id" :class="className" :style="{ height, width }" />
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
import * as echarts from "echarts";
|
|
import * as echarts from "echarts";
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
- id: {
|
|
|
|
- type: String,
|
|
|
|
- default: "radarChart",
|
|
|
|
- required: true,
|
|
|
|
- },
|
|
|
|
- className: {
|
|
|
|
- type: String,
|
|
|
|
- default: "chart",
|
|
|
|
- },
|
|
|
|
- width: {
|
|
|
|
- type: String,
|
|
|
|
- default: "400px",
|
|
|
|
- },
|
|
|
|
- height: {
|
|
|
|
- type: String,
|
|
|
|
- default: "300px",
|
|
|
|
- },
|
|
|
|
- // dataSets:[[28,38,45,32,25],[78,88,65,82,65]]
|
|
|
|
- dataSets: {
|
|
|
|
- type: Array,
|
|
|
|
- default: [],
|
|
|
|
- },
|
|
|
|
- // data:[78,88,65,82,65]
|
|
|
|
- data: {
|
|
|
|
- type: Array,
|
|
|
|
- default: [],
|
|
|
|
- },
|
|
|
|
- tag: {
|
|
|
|
- type: Boolean,
|
|
|
|
- default: false,
|
|
|
|
- },
|
|
|
|
|
|
+ id: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: "radarChart",
|
|
|
|
+ required: true,
|
|
|
|
+ },
|
|
|
|
+ className: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: "chart",
|
|
|
|
+ },
|
|
|
|
+ width: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: "400px",
|
|
|
|
+ },
|
|
|
|
+ height: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: "300px",
|
|
|
|
+ },
|
|
|
|
+ // dataSets:[[28,38,45,32,25],[78,88,65,82,65]]
|
|
|
|
+ dataSets: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: [] as Array<number>,
|
|
|
|
+ },
|
|
|
|
+ // star:[1,2,3,4,5]
|
|
|
|
+ star: {
|
|
|
|
+ type: Array,
|
|
|
|
+ default: [] as Array<number>,
|
|
|
|
+ },
|
|
|
|
+ tag: {
|
|
|
|
+ type: Boolean,
|
|
|
|
+ default: false,
|
|
|
|
+ },
|
|
});
|
|
});
|
|
// 是否有对比数据
|
|
// 是否有对比数据
|
|
const isCompare = props.dataSets?.length > 1;
|
|
const isCompare = props.dataSets?.length > 1;
|
|
let defaultData;
|
|
let defaultData;
|
|
let beforeData;
|
|
let beforeData;
|
|
if (isCompare) {
|
|
if (isCompare) {
|
|
- defaultData = props.dataSets?.[1];
|
|
|
|
- beforeData = props.dataSets?.[0];
|
|
|
|
|
|
+ defaultData = toRefs(props.dataSets?.[1]);
|
|
|
|
+ beforeData = toRefs(props.dataSets?.[0]);
|
|
} else {
|
|
} else {
|
|
- defaultData = props.data;
|
|
|
|
|
|
+ defaultData = toRefs(props.dataSets?.[0]);
|
|
}
|
|
}
|
|
|
|
|
|
const globalColor = {
|
|
const globalColor = {
|
|
- default: "#ffb72d",
|
|
|
|
- before: "#937dff",
|
|
|
|
- font: "#063b79",
|
|
|
|
- white: "#ffffff",
|
|
|
|
- red: "#F45028",
|
|
|
|
- orange: "#FF9F29",
|
|
|
|
- yellow: "#EDCB00",
|
|
|
|
- green: "#53BE07",
|
|
|
|
- blue: "#03C5EC"
|
|
|
|
|
|
+ default: "#ffb72d",
|
|
|
|
+ before: "#937dff",
|
|
|
|
+ font: "#063b79",
|
|
|
|
+ white: "#ffffff",
|
|
|
|
+ red: "#F45028",
|
|
|
|
+ orange: "#FF9F29",
|
|
|
|
+ yellow: "#EDCB00",
|
|
|
|
+ green: "#53BE07",
|
|
|
|
+ blue: "#03C5EC",
|
|
};
|
|
};
|
|
/**
|
|
/**
|
|
* 指示器 及 状态tag 自定义rich
|
|
* 指示器 及 状态tag 自定义rich
|
|
*/
|
|
*/
|
|
const tagBaseRich = (bgColor) => {
|
|
const tagBaseRich = (bgColor) => {
|
|
- return {
|
|
|
|
- color: globalColor.white,
|
|
|
|
- padding: [4, 10, 4, 10],
|
|
|
|
- borderRadius: 10,
|
|
|
|
- backgroundColor: bgColor
|
|
|
|
- };
|
|
|
|
|
|
+ return {
|
|
|
|
+ color: globalColor.white,
|
|
|
|
+ padding: [4, 10, 4, 10],
|
|
|
|
+ borderRadius: 10,
|
|
|
|
+ backgroundColor: bgColor,
|
|
|
|
+ };
|
|
};
|
|
};
|
|
const indicatorRich = {
|
|
const indicatorRich = {
|
|
- tit:{
|
|
|
|
- color: globalColor.font,
|
|
|
|
- fontSize: 14,
|
|
|
|
- padding: 5
|
|
|
|
- },
|
|
|
|
- red: tagBaseRich(globalColor.red),
|
|
|
|
- orange: tagBaseRich(globalColor.orange),
|
|
|
|
- yellow: tagBaseRich(globalColor.yellow),
|
|
|
|
- green: tagBaseRich(globalColor.green),
|
|
|
|
- blue: tagBaseRich(globalColor.blue)
|
|
|
|
-}
|
|
|
|
|
|
+ tit: {
|
|
|
|
+ color: globalColor.font,
|
|
|
|
+ fontSize: 14,
|
|
|
|
+ padding: 5,
|
|
|
|
+ },
|
|
|
|
+ red: tagBaseRich(globalColor.red),
|
|
|
|
+ orange: tagBaseRich(globalColor.orange),
|
|
|
|
+ yellow: tagBaseRich(globalColor.yellow),
|
|
|
|
+ green: tagBaseRich(globalColor.green),
|
|
|
|
+ blue: tagBaseRich(globalColor.blue),
|
|
|
|
+};
|
|
const indicatorFormatter = (name, indicator) => {
|
|
const indicatorFormatter = (name, indicator) => {
|
|
- if (!props.tag) {
|
|
|
|
- return `{tit|${name}}`;
|
|
|
|
- }
|
|
|
|
- const {star} = indicator;
|
|
|
|
- const label = [];
|
|
|
|
- label.push(`{tit|${name}}`);
|
|
|
|
- if (star === 1) {
|
|
|
|
- label.push(`{red|重度不足}`);
|
|
|
|
- }
|
|
|
|
- if (star === 2) {
|
|
|
|
- label.push("{orange|中等不足}");
|
|
|
|
- }
|
|
|
|
- if (star === 3) {
|
|
|
|
- label.push("{yellow|轻度不足}");
|
|
|
|
- }
|
|
|
|
- if (star === 4) {
|
|
|
|
- label.push("{green|良好}");
|
|
|
|
- }
|
|
|
|
- if (star === 5) {
|
|
|
|
- label.push("{blue|优秀}");
|
|
|
|
- }
|
|
|
|
- return label.join(`\n`);
|
|
|
|
-}
|
|
|
|
|
|
+ if (!props.tag) {
|
|
|
|
+ return `{tit|${name}}`;
|
|
|
|
+ }
|
|
|
|
+ const { star } = indicator;
|
|
|
|
+ const label = [];
|
|
|
|
+ label.push(`{tit|${name}}`);
|
|
|
|
+ if (star === 1) {
|
|
|
|
+ label.push(`{red|重度不足}`);
|
|
|
|
+ }
|
|
|
|
+ if (star === 2) {
|
|
|
|
+ label.push("{orange|轻度不足}");
|
|
|
|
+ }
|
|
|
|
+ if (star === 3) {
|
|
|
|
+ label.push("{yellow|中等水平}");
|
|
|
|
+ }
|
|
|
|
+ if (star === 4) {
|
|
|
|
+ label.push("{green|良好水平}");
|
|
|
|
+ }
|
|
|
|
+ if (star === 5) {
|
|
|
|
+ label.push("{blue|优秀水平}");
|
|
|
|
+ }
|
|
|
|
+ return label.join(`\n`);
|
|
|
|
+};
|
|
|
|
|
|
/**
|
|
/**
|
|
* 在图中定位每个数据的位置
|
|
* 在图中定位每个数据的位置
|
|
*/
|
|
*/
|
|
-const positionLabelData = (data, idx)=>{
|
|
|
|
- const labelValue = [0,0,0,0,0];
|
|
|
|
- labelValue[idx] = data[idx];
|
|
|
|
- // idx = 0,1,2,3,4 对应 top,left,left,right,right
|
|
|
|
- let pos = "bottom";
|
|
|
|
- if(idx=== 0) {
|
|
|
|
- pos = "top";
|
|
|
|
- }
|
|
|
|
- if(idx === 1 || idx === 2) {
|
|
|
|
- pos = "left";
|
|
|
|
- }
|
|
|
|
- if(idx === 3 || idx === 4) {
|
|
|
|
- pos = "right";
|
|
|
|
- }
|
|
|
|
- return {
|
|
|
|
- value: labelValue,
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- fontSize: 12,
|
|
|
|
- position: pos,
|
|
|
|
- formatter: (params) => {
|
|
|
|
- return params.value > 0 ? params.value : "";
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-}
|
|
|
|
|
|
+const positionLabelData = (data, idx) => {
|
|
|
|
+ const labelValue = [0, 0, 0, 0, 0];
|
|
|
|
+ labelValue[idx] = data[idx];
|
|
|
|
+ // idx = 0,1,2,3,4 对应 top,left,left,right,right
|
|
|
|
+ let pos = "bottom";
|
|
|
|
+ if (idx === 0) {
|
|
|
|
+ pos = "top";
|
|
|
|
+ }
|
|
|
|
+ if (idx === 1 || idx === 2) {
|
|
|
|
+ pos = "left";
|
|
|
|
+ }
|
|
|
|
+ if (idx === 3 || idx === 4) {
|
|
|
|
+ pos = "right";
|
|
|
|
+ }
|
|
|
|
+ return {
|
|
|
|
+ value: labelValue,
|
|
|
|
+ label: {
|
|
|
|
+ show: true,
|
|
|
|
+ fontSize: 12,
|
|
|
|
+ position: pos,
|
|
|
|
+ formatter: (params) => {
|
|
|
|
+ return params.value > 0 ? params.value : "";
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+};
|
|
const positionFormatter = (data) => {
|
|
const positionFormatter = (data) => {
|
|
- const result = [];
|
|
|
|
- for (let idx in data) {
|
|
|
|
- result.push(positionLabelData(data, idx*1));
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
-}
|
|
|
|
|
|
+ const result = [];
|
|
|
|
+ for (let idx in data) {
|
|
|
|
+ result.push(positionLabelData(data, idx * 1));
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+};
|
|
/**
|
|
/**
|
|
* 配置项
|
|
* 配置项
|
|
*/
|
|
*/
|
|
const options = {
|
|
const options = {
|
|
- color: [globalColor.default],
|
|
|
|
- legend: {
|
|
|
|
- right: "5%",
|
|
|
|
- top: "5%",
|
|
|
|
- data: [{ name: "训练前", icon: "circle" }, { name: "训练后", icon: "circle" }],
|
|
|
|
- textStyle: { fontSize: 12},
|
|
|
|
- show: false
|
|
|
|
- },
|
|
|
|
- radar: {
|
|
|
|
- radius: "50%",
|
|
|
|
- center: ["50%", "55%"],
|
|
|
|
- // 指示器 及 状态tag
|
|
|
|
- indicator: [
|
|
|
|
- { name: "专注力平均值", max: 100, star: 1},
|
|
|
|
- { name: "高专注占比", max: 100, star: 2},
|
|
|
|
- { name: "专注唤醒效率", max: 100, star: 3},
|
|
|
|
- { name: "整体和谐度", max: 100, star: 4},
|
|
|
|
- { name: "专注力稳定度", max: 100, star: 5},
|
|
|
|
- ],
|
|
|
|
- axisName: {
|
|
|
|
- rich: indicatorRich,
|
|
|
|
- formatter: indicatorFormatter,
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- series: [
|
|
|
|
- // 数据分散定位
|
|
|
|
- {
|
|
|
|
- name: "训练后",
|
|
|
|
- type: "radar",
|
|
|
|
- symbolSize: 0,
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- color: globalColor.default,
|
|
|
|
- fontSize: 16,
|
|
|
|
- distance: 5
|
|
|
|
- },
|
|
|
|
- lineStyle:{width:0},
|
|
|
|
- data:positionFormatter(defaultData)
|
|
|
|
- },
|
|
|
|
- // 覆盖区域的样式
|
|
|
|
- {
|
|
|
|
- name: "训练前 vs 训练后",
|
|
|
|
- type: "radar",
|
|
|
|
- symbolSize: 5,
|
|
|
|
- data: [
|
|
|
|
- {
|
|
|
|
- value: defaultData,
|
|
|
|
- name: "训练后",
|
|
|
|
- lineStyle:{color: globalColor.default},
|
|
|
|
- itemStyle:{color: globalColor.default},
|
|
|
|
- areaStyle: {
|
|
|
|
- color: globalColor.default,
|
|
|
|
- opacity: .5
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- ],
|
|
|
|
- },
|
|
|
|
- ]
|
|
|
|
|
|
+ color: [globalColor.default],
|
|
|
|
+ legend: {
|
|
|
|
+ right: "5%",
|
|
|
|
+ top: "5%",
|
|
|
|
+ data: [
|
|
|
|
+ { name: "训练前", icon: "circle" },
|
|
|
|
+ { name: "训练后", icon: "circle" },
|
|
|
|
+ ],
|
|
|
|
+ textStyle: { fontSize: 12 },
|
|
|
|
+ show: false,
|
|
|
|
+ },
|
|
|
|
+ radar: {
|
|
|
|
+ radius: "50%",
|
|
|
|
+ center: ["50%", "55%"],
|
|
|
|
+ // 指示器 及 状态tag
|
|
|
|
+ indicator: [
|
|
|
|
+ { name: "专注力平均值", max: 100, star: props.star?.[0] },
|
|
|
|
+ { name: "高专注占比", max: 100, star: props.star?.[1] },
|
|
|
|
+ { name: "专注唤醒效率", max: 100, star: props.star?.[2] },
|
|
|
|
+ { name: "整体和谐度", max: 100, star: props.star?.[3] },
|
|
|
|
+ { name: "专注力稳定度", max: 100, star: props.star?.[4] },
|
|
|
|
+ ],
|
|
|
|
+ axisName: {
|
|
|
|
+ rich: indicatorRich,
|
|
|
|
+ formatter: indicatorFormatter,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ // 数据分散定位
|
|
|
|
+ {
|
|
|
|
+ name: "训练后",
|
|
|
|
+ type: "radar",
|
|
|
|
+ symbolSize: 0,
|
|
|
|
+ label: {
|
|
|
|
+ show: true,
|
|
|
|
+ color: globalColor.default,
|
|
|
|
+ fontSize: 16,
|
|
|
|
+ distance: 5,
|
|
|
|
+ },
|
|
|
|
+ lineStyle: { width: 0 },
|
|
|
|
+ data: positionFormatter(defaultData),
|
|
|
|
+ },
|
|
|
|
+ // 覆盖区域的样式
|
|
|
|
+ {
|
|
|
|
+ name: "训练前 vs 训练后",
|
|
|
|
+ type: "radar",
|
|
|
|
+ symbolSize: 5,
|
|
|
|
+ data: [
|
|
|
|
+ {
|
|
|
|
+ value: defaultData,
|
|
|
|
+ name: "训练后",
|
|
|
|
+ lineStyle: { color: globalColor.default },
|
|
|
|
+ itemStyle: { color: globalColor.default },
|
|
|
|
+ areaStyle: {
|
|
|
|
+ color: globalColor.default,
|
|
|
|
+ opacity: 0.5,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
};
|
|
};
|
|
const getOptions = () => {
|
|
const getOptions = () => {
|
|
- if(isCompare){
|
|
|
|
- options.color = [globalColor.before, globalColor.default];
|
|
|
|
- options.legend.show = true;
|
|
|
|
- options.series[1].data.unshift({
|
|
|
|
- value: beforeData,
|
|
|
|
- name: "训练前",
|
|
|
|
- lineStyle:{color: globalColor.before},
|
|
|
|
- itemStyle:{color: globalColor.before},
|
|
|
|
- areaStyle: {
|
|
|
|
- color: globalColor.before,
|
|
|
|
- opacity: .5
|
|
|
|
- },
|
|
|
|
- });
|
|
|
|
- options.series.unshift({
|
|
|
|
- name: "训练前",
|
|
|
|
- type: "radar",
|
|
|
|
- symbolSize: 0,
|
|
|
|
- label: {
|
|
|
|
- show: true,
|
|
|
|
- color: globalColor.before,
|
|
|
|
- fontSize: 16,
|
|
|
|
- //distance: 5
|
|
|
|
- },
|
|
|
|
- lineStyle:{width:0},
|
|
|
|
- data:positionFormatter(beforeData)
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- return options;
|
|
|
|
-}
|
|
|
|
|
|
+ if (isCompare) {
|
|
|
|
+ options.color = [globalColor.before, globalColor.default];
|
|
|
|
+ options.legend.show = true;
|
|
|
|
+ options.series[1].data.unshift({
|
|
|
|
+ value: beforeData,
|
|
|
|
+ name: "训练前",
|
|
|
|
+ lineStyle: { color: globalColor.before },
|
|
|
|
+ itemStyle: { color: globalColor.before },
|
|
|
|
+ areaStyle: {
|
|
|
|
+ color: globalColor.before,
|
|
|
|
+ opacity: 0.5,
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+ options.series.unshift({
|
|
|
|
+ name: "训练前",
|
|
|
|
+ type: "radar",
|
|
|
|
+ symbolSize: 0,
|
|
|
|
+ label: {
|
|
|
|
+ show: true,
|
|
|
|
+ color: globalColor.before,
|
|
|
|
+ fontSize: 16,
|
|
|
|
+ //distance: 5
|
|
|
|
+ },
|
|
|
|
+ lineStyle: { width: 0 },
|
|
|
|
+ data: positionFormatter(beforeData),
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ return options;
|
|
|
|
+};
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
- const chart = echarts.init(
|
|
|
|
- document.getElementById(<string>props.id) as HTMLDivElement
|
|
|
|
- );
|
|
|
|
- chart.setOption(getOptions());
|
|
|
|
|
|
+ const chart = echarts.init(
|
|
|
|
+ document.getElementById(<string>props.id) as HTMLDivElement
|
|
|
|
+ );
|
|
|
|
+ chart.setOption(getOptions());
|
|
|
|
|
|
- window.addEventListener("resize", () => {
|
|
|
|
- chart.resize();
|
|
|
|
- });
|
|
|
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
|
+ chart.resize();
|
|
|
|
+ });
|
|
});
|
|
});
|
|
</script>
|
|
</script>
|