You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
4.3 KiB
215 lines
4.3 KiB
|
4 years ago
|
<template>
|
||
|
|
<div class="m-chart">
|
||
|
|
<canvas id="myChart" width="400" height="260"></canvas>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
import nextTick from "dai-js/tools/nextTick";
|
||
|
|
// ios下字体渲染有bug
|
||
|
|
const fontFamily = "PingFang SC";
|
||
|
|
const fontSize = 14;
|
||
|
|
|
||
|
|
let chart;
|
||
|
|
let srcData = [];
|
||
|
|
|
||
|
|
let textShapeList = [];
|
||
|
|
const addTextShape = () => {
|
||
|
|
if (textShapeList.length > 0) {
|
||
|
|
textShapeList.forEach((item) => {
|
||
|
|
item.remove(true);
|
||
|
|
});
|
||
|
|
textShapeList = [];
|
||
|
|
}
|
||
|
|
// 添加折线上文本
|
||
|
|
const canvas = chart.get("canvas");
|
||
|
|
const group = canvas.addGroup();
|
||
|
|
const shapes = {};
|
||
|
|
|
||
|
|
function addFn(list) {
|
||
|
|
const listLength = list.length;
|
||
|
|
list.forEach(function (obj, index) {
|
||
|
|
// 避免显示太多,乱七八糟
|
||
|
|
if (listLength > 7 && index > 0 && index < listLength - 1) {
|
||
|
|
if (index % Math.ceil(listLength / 5) != 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const offsetX = 6;
|
||
|
|
const offsetY = 1;
|
||
|
|
const point = chart.getPosition(obj);
|
||
|
|
const text = group.addShape("text", {
|
||
|
|
attrs: {
|
||
|
|
x: obj.type === "支持" ? point.x + 2 * offsetX : point.x - offsetX,
|
||
|
|
y: point.y + offsetY,
|
||
|
|
text: obj.value,
|
||
|
|
textAlign: "center",
|
||
|
|
textBaseline: "bottom",
|
||
|
|
fill: "#333",
|
||
|
|
fontWeight: 500,
|
||
|
|
fontFamily,
|
||
|
|
fontSize,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
textShapeList.push(text); // 缓存该 shape, 便于后续查找
|
||
|
|
});
|
||
|
|
}
|
||
|
|
srcData.sort((a, b) => {
|
||
|
|
return new Date(a.date).getTime() - new Date(b.date).getTime();
|
||
|
|
});
|
||
|
|
let supData = srcData.filter((item) => item.type == "支持");
|
||
|
|
let oppData = srcData.filter((item) => item.type == "反对");
|
||
|
|
addFn(supData);
|
||
|
|
addFn(oppData);
|
||
|
|
};
|
||
|
|
|
||
|
|
const iniChart = function (config, srcData) {
|
||
|
|
chart = new window.F2.Chart({
|
||
|
|
id: "myChart",
|
||
|
|
...config,
|
||
|
|
});
|
||
|
|
|
||
|
|
const supColor = "#FFDA0E";
|
||
|
|
const oppColor = "#00E5ED";
|
||
|
|
|
||
|
|
chart.source(srcData, {
|
||
|
|
date: {
|
||
|
|
range: [0, 1],
|
||
|
|
type: "timeCat",
|
||
|
|
mask: "MM-DD",
|
||
|
|
},
|
||
|
|
value: {
|
||
|
|
// type: "linear",
|
||
|
|
},
|
||
|
|
});
|
||
|
|
// 设置坐标轴
|
||
|
|
chart.axis("date", {
|
||
|
|
line: {
|
||
|
|
lineWidth: 1,
|
||
|
|
stroke: "#E7EEEE",
|
||
|
|
},
|
||
|
|
label: {
|
||
|
|
fontWeight: 500,
|
||
|
|
fontSize,
|
||
|
|
fill: "#B5B7BF",
|
||
|
|
textBaseline: "middle",
|
||
|
|
},
|
||
|
|
labelOffset: 25,
|
||
|
|
country: {
|
||
|
|
range: [0.1, 0.9], // 配置 range 范围,使左右两边不留边距
|
||
|
|
},
|
||
|
|
grid: null,
|
||
|
|
});
|
||
|
|
chart.axis("value", {
|
||
|
|
line: {
|
||
|
|
lineWidth: 1,
|
||
|
|
stroke: "#E7EEEE",
|
||
|
|
},
|
||
|
|
labelOffset: 20,
|
||
|
|
label: {
|
||
|
|
fontWeight: 500,
|
||
|
|
fontSize,
|
||
|
|
fill: "#B5B7BF",
|
||
|
|
},
|
||
|
|
});
|
||
|
|
// 类别标识区
|
||
|
|
chart.legend({
|
||
|
|
position: "bottom",
|
||
|
|
align: "center",
|
||
|
|
offsetY: -30,
|
||
|
|
custom: true,
|
||
|
|
nameStyle: {
|
||
|
|
fill: "#999",
|
||
|
|
fontWeight: 500,
|
||
|
|
fontSize,
|
||
|
|
},
|
||
|
|
itemWidth: 150,
|
||
|
|
wordSpace: 25,
|
||
|
|
items: [
|
||
|
|
{
|
||
|
|
name: "支持",
|
||
|
|
marker(x, y, r, ctx) {
|
||
|
|
ctx.lineWidth = 10;
|
||
|
|
ctx.strokeStyle = supColor;
|
||
|
|
ctx.moveTo(x - r - 15, y);
|
||
|
|
ctx.lineTo(x + r + 15, y);
|
||
|
|
ctx.stroke();
|
||
|
|
ctx.fill();
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "反对",
|
||
|
|
marker(x, y, r, ctx) {
|
||
|
|
ctx.lineWidth = 10;
|
||
|
|
ctx.strokeStyle = oppColor;
|
||
|
|
ctx.moveTo(x - r - 15, y);
|
||
|
|
ctx.lineTo(x + r + 15, y);
|
||
|
|
ctx.stroke();
|
||
|
|
ctx.fill();
|
||
|
|
},
|
||
|
|
},
|
||
|
|
],
|
||
|
|
});
|
||
|
|
// 添加折线
|
||
|
|
chart
|
||
|
|
.line()
|
||
|
|
.position("date*value")
|
||
|
|
.color("type", (type) => {
|
||
|
|
if (type === "支持") {
|
||
|
|
return supColor;
|
||
|
|
}
|
||
|
|
return oppColor;
|
||
|
|
})
|
||
|
|
.style("type", {
|
||
|
|
lineWidth: 1,
|
||
|
|
})
|
||
|
|
.animate();
|
||
|
|
chart.render();
|
||
|
|
|
||
|
|
addTextShape();
|
||
|
|
|
||
|
|
// 注意:需要把chart return 出来
|
||
|
|
return chart;
|
||
|
|
};
|
||
|
|
|
||
|
|
export default {
|
||
|
|
name: "chart",
|
||
|
|
props: {
|
||
|
|
list: {
|
||
|
|
type: Array,
|
||
|
|
default: () => {
|
||
|
|
return [];
|
||
|
|
},
|
||
|
|
},
|
||
|
|
config: {
|
||
|
|
type: Object,
|
||
|
|
default: () => {
|
||
|
|
return {};
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
iniLoading: false,
|
||
|
|
};
|
||
|
|
},
|
||
|
|
watch: {
|
||
|
|
list(data) {
|
||
|
|
chart.changeData(data);
|
||
|
|
srcData = data;
|
||
|
|
addTextShape();
|
||
|
|
},
|
||
|
|
},
|
||
|
|
async created() {
|
||
|
|
await nextTick(200);
|
||
|
|
iniChart(this.config, this.list);
|
||
|
|
await nextTick(200);
|
||
|
|
this.iniLoading = true;
|
||
|
|
},
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style lang="scss" scoped></style>
|