vue3+ts项目中封装单柱的柱状图
成品图
下载echarts npm i echarts
封装组件为Barchart.vue文件
<template>
</template>
<script setup lang="ts">
import { nextTick, watch } from 'vue'
import echarts from '@/assets/ts/echarts';
import useResizeChart from '@/hooks/useResizeChart';
import { CustomChart } from 'echarts/charts';
// import { LegendComponent } from 'echarts/components';
// import { LegendComponent } from 'echarts/types/dist/components';
echarts.use([ CustomChart]);
//合并配置项
function mergeConfig(defaultConfig: object, config: object) {
return Object.assign(defaultConfig, config);
}
//向外接收
const props = defineProps({
pid: {
type: String,
required: true,
},
title: {
type: Object,
default: {},
},
xAxisData: {
type: Array,
required: true,
},
legend: {
type: Object,
default: {},
},
grid: {
type: Object,
default: {},
},
XAxisLine: {
type: Object,
default: {},
},
YAxisLine: {
type: Object,
default: {},
},
yUnit: {
type: String,
default: '',
},
XSplitLine: {
type: Object,
default: {},
},
YSplitLine: {
type: Object,
default: {},
},
XAxisTick: {
type: Object,
default: {},
},
YAxisTick: {
type: Object,
default: {},
},
config: {
type: Object as () => echarts.EChartsCoreOption,
default: {},
},
value: {
type: Array,
required: true,
},
// 柱子的颜色
color: {
type: Array,
default: ['rgba(29, 230, 235,1)', 'rgba(7, 235, 251,1)'],
},
});
function initOption(): echarts.EChartsCoreOption {
// 绘制左侧面
const CubeLeft = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath: function (ctx, shape) {
// 会canvas的应该都能看得懂,shape是从custom传入的
const xAxisPoint = shape.xAxisPoint;
const c0 = [shape.x + 3.5, shape.y];
const c1 = [shape.x - 11.5, shape.y - 3];
const c2 = [xAxisPoint[0] - 11.5, xAxisPoint[1] - 6.5];
const c3 = [xAxisPoint[0] + 3.5, xAxisPoint[1]];
ctx.moveTo(c0[0], c0[1])
// @ts-ignore
.lineTo(c1[0], c1[1])
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.closePath();
},
});
// 绘制右侧面
const CubeRight = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath: function (ctx, shape) {
const xAxisPoint = shape.xAxisPoint;
const c1 = [shape.x + 3, shape.y];
const c2 = [xAxisPoint[0] + 3, xAxisPoint[1]];
const c3 = [xAxisPoint[0] + 12, xAxisPoint[1] - 7];
const c4 = [shape.x + 12, shape.y - 7];
ctx.moveTo(c1[0], c1[1])
// @ts-ignore
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.lineTo(c4[0], c4[1])
.closePath();
},
});
// 绘制顶面
const CubeTop = echarts.graphic.extendShape({
shape: {
x: 0,
y: 0,
},
buildPath: function (ctx, shape) {
const c1 = [shape.x + 3.5, shape.y];
const c2 = [shape.x + 12.5, shape.y - 7.5]; //右点
const c3 = [shape.x - 2.5, shape.y - 10];
const c4 = [shape.x - 11.5, shape.y - 3];
ctx.moveTo(c1[0], c1[1])
// @ts-ignore
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.lineTo(c4[0], c4[1])
.closePath();
},
});
// 注册三个面图形
echarts.graphic.registerShape('CubeLeft', CubeLeft);
echarts.graphic.registerShape('CubeRight', CubeRight);
echarts.graphic.registerShape('CubeTop', CubeTop);
//接收x轴值
const VALUE = props.value;
const series =[
//自带顶部数值样式
{
type: 'bar',
label: {
show: true,
position: 'top',
fontSize: 14,
color: props.color[0],
offset: [2, -10],
},
itemStyle: {
color: 'transparent',
},
tooltip: {},
data: VALUE,
},
{
type: 'custom',
renderItem: (params:any, api:any) => {
const location = api.coord([api.value(0), api.value(1)]);
//定义三个面,每个面颜色
let cubeLeftStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
// @ts-ignore
color: props.color[0],
},
{
offset: 1,
color: 'rgba(7, 20, 52,0.7)',
},
]);
let cubeRightStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(7, 20, 52,1)',
},
{
offset: 1,
// @ts-ignore
color: props.color[0],
},
]);
let cubeTopStyle = new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
// @ts-ignore
color: props.color[1] || props.color[0],
},
]);
return {
type: 'group',
/*(2)根据数据转换成坐标系中的坐标点
api.coord([x,y])
*/
children: [
{
//左平面样式
type: 'CubeLeft',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
//此处表示左侧面的面的长度
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
fill:cubeLeftStyle
},
},
{
// 右平面
type: 'CubeRight',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
fill:cubeRightStyle
},
},
{
// 上平面
type: 'CubeTop',
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: location[0],
y: location[1],
xAxisPoint: api.coord([api.value(0), api.value(1)]),
},
style: {
fill: cubeTopStyle
},
},
],
};
},
// color: 'blue',
data: VALUE,
},
]
//标题样式
const title = mergeConfig({
show: true,
text: '',
left: 'center',
textStyle: {
color: "#333",
fontSize: 20
},
}, props.title);
//x轴字体样式
const XAxisLine = mergeConfig({
show: true,
lineStyle: {
color: "#333",
type: 'solid',
width: 1
},
}, props.XAxisLine);
const YAxisLine = mergeConfig({
show: false,
lineStyle: {
show: true,
lineStyle: {
color: "#fff",
type: 'solid',
width: 1
},
},
}, props.YAxisLine);
//x轴刻度线
const XSplitLine = mergeConfig({
show: false,
lineStyle: {
color: "#333",
type: 'dotted',
width: 1
},
}, props.XSplitLine);
//y轴刻度线
const YSplitLine = mergeConfig({
show: true,
lineStyle: {
color: "#ECECEC",
type: 'dashed',
width: 1
},
}, props.YSplitLine);
const XAxisTick = mergeConfig({
show: false,
length: 5,
inside: true,
alignWithLabel: true,
lineStyle: {
color: "#333",
type: 'solid',
width: 1
},
}, props.XAxisTick);
const YAxisTick = mergeConfig({
show: false,
length: 5,
inside: true,
alignWithLabel: true,
lineStyle: {
color: "#333",
type: 'solid',
width: 1
},
}, props.YAxisTick);
const legend = mergeConfig({
show: true,
left: "center",
top: "90%",
icon: 'rect'
}, props.legend)
const grid = mergeConfig(
{
left: '5%',
right: '5%',
top: '12%',
bottom: '0%',
containLabel: true,
},
props.grid,
);
let option: echarts.EChartsCoreOption = {
title,
// grid: {
// top: '10%',
// left: '5%',
// bottom: '15%',
// right: '0%',
// },
tooltip: {
trigger: "axis",
//阴影提示器
axisPointer: {
type: 'shadow',
shadowStyle:{
shadowColor:'#2e3e51' //阴影颜色
}
},
//显示提示器内数据
formatter:function(params){
const item=params[1]
return item.name + ' : ' + item.value;
},
// 提示框背景颜色
backgroundColor: '#122843',
// 提示框边框颜色
borderColor: '#42D1F1',
// 提示框文本样式
textStyle: {
color: '#fff',
},
},
legend:legend,
grid:grid,
xAxis: {
type: 'category',
// boundaryGap: false,
data: props.xAxisData,
axisLine: XAxisLine,
splitLine: XSplitLine,
axisTick: XAxisTick,
axisLabel: {
//x轴文字的配置
show: true,
color: '#fff',
fontSize: 12,
rotate: 30,
},
},
yAxis: {
type: 'value',
name: props.yUnit,
nameTextStyle: {
color: '#fff',
fontSize: 16,
},
axisLine: YAxisLine,
splitLine: YSplitLine,
axisTick: YAxisTick,
axisLabel: {
//y轴文字的配置
color: '#fff',
fontSize: 12,
},
},
series
};
option = Object.assign(option, props.config);
return option;
}
//通用 初始化 option
let option = initOption();
let container: HTMLElement | null = null;
let myChart: echarts.ECharts | null = null;
const renderChart = (notMerge: boolean = false) => {
if (!myChart) myChart = echarts.init(container as HTMLElement);
myChart.setOption(option, {
notMerge,
});
};
//更新视图
nextTick(() => {
container = document.querySelector('#' + props.pid) as HTMLElement;
renderChart();
useResizeChart(container, myChart as echarts.ECharts);
});
//开启监听,监听变化
watch(
//监听props变化进行动态更新数据
()=>props,
(newVal,oldVal)=>{
// 开启
let notMerge = true;
option = initOption();
renderChart(notMerge);
}
)
//导出图片功能
// function exportImg() {
// const src = (myChart as echarts.ECharts).getDataURL({
// pixelRatio: 2,
// backgroundColor: '#08172A'
// });
// const a = document.createElement('a');
// a.href = src;
// a.download = (option.title as { text: string }).text || "chart-img";
// a.click();
// }
// defineExpose({
// exportImg
// });
</script>
<style lang="scss" scoped>
</style>
使用组件
<template>
<div id="CO-info" >
<BarThreeCharts pid="CO-info" :value="COValue" :xAxisData="tunnelList"></BarThreeCharts>
</div>
</template>
<script setup lang="ts">
const COValue = [12, 23, 13, 46, 53, 26, 17, 8, 19, 23, 14, 33, 42];
const tunnelList = ['苍龙峡', '云雾山', '白鹿塬', '铜钱峡', '堡子村', '北辰公园', '双沟桥', '新桥村1#', '新桥村2#', '农光村', '元岭村', '石磨村', '白家崖'];
</script>
<style lang="scss" scoped>
#CO-info {
width: 100%;
height: vh(265);
}
</style >
3d柱状图要注意创建左切面,右切面和上切面 三种颜色形成3d柱状效果
切换
推荐vue3封装echarts博客地址 https://www.jb51.net/article/267642.htm
import useResizeChart from '@/hooks/useResizeChart';
useResizeChart.ts文件
// 用于自适应 echarts 图表大小
import echarts from "@/assets/ts/echarts";
export default function useResizeChart(container: HTMLElement, chart: echarts.ECharts) {
// 监听容器大小变化
const resizeObserver = new ResizeObserver(entries => {
// 重新设置大小
chart.resize({
animation: {
duration: 500
}
});
});
resizeObserver.observe(container);
// onBeforeUnmount(() => {
// // 销毁前解除监听
// resizeObserver.unobserve(container);
// })
}
知识点补充
api.coord
api.coord(...),意思是进行坐标转换计算。例如 var point = api.coord([api.value(0), api.value(1)]) 表示 dataItem 中的数值转换成坐标系上的点.
Object.assign(target,..sources)
参数;taget ==>目标对象 source==>源对象
返回值:target,即目标对象
例:
var target={name:'guxin',age:18}
var source={state:'signle',age:22}
var result=Object.assign(target,source)
console.log(target)