效果:
迷你趋势图实现参考抛开echarts手动实现迷你趋势图_echarts 趋势图-CSDN博客
渐变色实现如下:
<template>
<div>
<div v-html="svg" class="svg"></div>
</div>
</template>
<script>
export default {
data() {
return {
svg: "",
};
},
mounted() {
//渲染svg
const generateSvg = (data, width, height) => {
const maxValue = Math.max(...data);
const minValue = Math.min(...data.filter((i) => i !== null));
const range = maxValue - minValue;
const margin = 2;
const points = data.map((value, index) => {
const x = (index / (data.length - 1)) * width;
const y =
height -
margin -
((value - minValue) / range) * (height - 2 * margin) || 0;
return { x, y, isZero: value == null };
});
const pathData = generatePathData(points);
const pathData2 = generatePathData2(points, height);
// console.log(points)
return `<svg width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" style="width:100%" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">
<path d="${pathData}" stroke="#003A90" fill="transparent" stroke-width="2" >
</path>
<defs>
<linearGradient id="areaGradient" x1="50%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="rgba(195,220,254, 0.7)" />
<stop offset="100%" stop-color="rgba(244,250,254, 0.1)" />
</linearGradient>
</defs>
<path
d="${pathData2}"
fill="url(#areaGradient)"
stroke="none"
stroke-width="2"
/>
</svg>
`;
};
const generatePathData = (points) => {
const pathData = points.reduce((acc, point, i, arr) => {
if (point.isZero) {
if (i == points.length - 1) {
// 到最后一个点时设置最低点
acc += ` C ${point.x},${height} ${point.x},${height} ${point.x},${height}`
}
return acc; // 跳过空点
}
const previousPoint = arr[i - 1]; // 上一点
if (i === 0 || previousPoint.isZero) {
// 如果是第一个点或前一个点是空的,则移动到当前点
acc += `M ${point.x},${point.y}`;
} else {
// 使用贝塞尔曲线连接非空点
const controlPointX = (previousPoint.x + point.x) / 2;
acc += ` C ${controlPointX},${previousPoint.y} ${controlPointX},${point.y} ${point.x},${point.y}`;
}
return acc;
}, "");
return pathData;
};
const generatePathData2 = (points, height) => {
const pathData = points.reduce((acc, point, i, arr) => {
if (point.isZero) {
return acc; // 跳过空点
}
const previousPoint = arr[i - 1]; // 上一点
if (i === 0 || previousPoint.isZero) {
// 设置最低点
acc += `M ${point.x},${height}`;
} else {
// 使用贝塞尔曲线连接非空点
const controlPointX = (previousPoint.x + point.x) / 2;
acc += ` C ${controlPointX},${previousPoint.y} ${controlPointX},${point.y} ${point.x},${point.y}`;
// acc += ` C ${controlPointX},${previousPoint.y} ${controlPointX},${point.y} ${point.x},${i==points.length-1?height:point.y}`
if (i == points.length - 1) {
// 到最后一个点时设置最低点
acc += ` C ${point.x},${point.y} ${point.x},${point.y} ${point.x},${height}`;
}
}
return acc;
}, "");
return pathData;
};
const data = [20, 0, 100, 0, 0, 30, 50, 0, 0, 60, 80, 90, 100];
//const data = [100, 100, 0, 100, 100, 100, 100, 100];
this.svg = generateSvg(data, 200, 50);
},
};
</script>
<style lang="less" scoped>
.svg{
width: 200px;
height: 50px;
}
</style>