|
@@ -0,0 +1,252 @@
|
|
|
+<!-- 五维雷达图 -->
|
|
|
+<template>
|
|
|
+ <div :id="id" :class="className" :style="{ height, width }" />
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import * as echarts from "echarts";
|
|
|
+
|
|
|
+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,
|
|
|
+ },
|
|
|
+});
|
|
|
+// 是否有对比数据
|
|
|
+const isCompare = props.dataSets?.length > 1;
|
|
|
+let defaultData;
|
|
|
+let beforeData;
|
|
|
+if (isCompare) {
|
|
|
+ defaultData = props.dataSets?.[1];
|
|
|
+ beforeData = props.dataSets?.[0];
|
|
|
+} else {
|
|
|
+ defaultData = props.data;
|
|
|
+}
|
|
|
+
|
|
|
+const globalColor = {
|
|
|
+ default: "#ffb72d",
|
|
|
+ before: "#937dff",
|
|
|
+ font: "#063b79",
|
|
|
+ white: "#ffffff",
|
|
|
+ red: "#F45028",
|
|
|
+ orange: "#FF9F29",
|
|
|
+ yellow: "#EDCB00",
|
|
|
+ green: "#53BE07",
|
|
|
+ blue: "#03C5EC"
|
|
|
+};
|
|
|
+/**
|
|
|
+ * 指示器 及 状态tag 自定义rich
|
|
|
+ */
|
|
|
+const tagBaseRich = (bgColor) => {
|
|
|
+ return {
|
|
|
+ color: globalColor.white,
|
|
|
+ padding: [4, 10, 4, 10],
|
|
|
+ borderRadius: 10,
|
|
|
+ backgroundColor: bgColor
|
|
|
+ };
|
|
|
+};
|
|
|
+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)
|
|
|
+}
|
|
|
+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`);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 在图中定位每个数据的位置
|
|
|
+ */
|
|
|
+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 result = [];
|
|
|
+ for (let idx in data) {
|
|
|
+ result.push(positionLabelData(data, idx*1));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 配置项
|
|
|
+ */
|
|
|
+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
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ]
|
|
|
+};
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const chart = echarts.init(
|
|
|
+ document.getElementById(<string>props.id) as HTMLDivElement
|
|
|
+ );
|
|
|
+ chart.setOption(getOptions());
|
|
|
+
|
|
|
+ window.addEventListener("resize", () => {
|
|
|
+ chart.resize();
|
|
|
+ });
|
|
|
+});
|
|
|
+</script>
|