首页 前端知识 vue3 ts项目中封装3d单柱柱状图

vue3 ts项目中封装3d单柱柱状图

2024-08-24 23:08:15 前端知识 前端哥 543 933 我要收藏

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)

转载请注明出处或者链接地址:https://www.qianduange.cn//article/16821.html
标签
评论
发布的文章

LoopBack组件JSONAPI使用指南

2024-09-04 23:09:43

编译JSONCPP源码

2024-09-04 23:09:49

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!