0


echarts实现3d柱状图的两种方式

echarts实现3d柱状图的两种方式

看了不少关于3d柱状图的案例,发现做3d柱状图 常用的两种方式就是 自定义图形和象型柱图, 两种实现方式效果如下:
在这里插入图片描述

方法1: echarts.graphic.extendShape 自定义图形

echarts自定义图形的详细用法点这里, 官网点这里, 图中第一个3d柱状图我参考的案例在这里, 看了很多 echarts这种3d案例, 自定义图形做3d柱状图,貌似只能有个柱子(可能 能做双柱,但是 我真的不会)

封装成组件的完整代码如下:

<template></template><script setup lang="ts">import{ nextTick, watch }from'vue';import echarts from'@/assets/ts/echarts';import useResizeChart from'@/hooks/useResizeChart';functionmergeConfig(defaultConfig: object, config: object){return Object.assign(defaultConfig, config);}functioninitOption(): 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);constVALUE= props.value;const series =[{
            type:'custom',renderItem:(params:any, api:any)=>{let cubeLeftStyle =newecharts.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 =newecharts.graphic.LinearGradient(0,0,0,1,[{
                        offset:0,
                        color:'rgba(7, 20, 52,1)',},{
                        offset:1,// @ts-ignore

                        color: props.color[0],},]);let cubeTopStyle =newecharts.graphic.LinearGradient(0,0,0,1,[{
                        offset:0,// @ts-ignore
                        color: props.color[1]|| props.color[0],},]);const location = api.coord([api.value(0), api.value(1)]);return{
                    type:'group',
                    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),0]),},
                            style:{
                                fill: cubeTopStyle,},},],};},
            data:VALUE,},{
            type:'bar',
            label:{
                show:true,
                position:'top',
                fontSize:14,
                color: props.color[0],
                offset:[2,-10],},
            itemStyle:{
                color:'transparent',},
            tooltip:{},
            data:VALUE,},];const title =mergeConfig({
            text:'',
            textStyle:{
                color: props.color[0],
                fontWeight:'800',
                fontSize:12,},
            left:'18px',
            top:'1%',},
        props.title,);const XAxisLine =mergeConfig({
            show:false,
            lineStyle:{
                type:'solid',
                width:1,
                color:'#2c3954',},},
        props.XAxisLine,);const YAxisLine =mergeConfig({
            show:false,
            lineStyle:{
                show:true,
                lineStyle:{
                    type:'solid',
                    width:1,},},},
        props.YAxisLine,);const legend =mergeConfig({
            show:true,
            left:'center',
            top:'95%',
            icon:'circle',
            textStyle:{
                color:'#fff',},},
        props.legend,);const grid =mergeConfig({
            left:'5%',
            right:'5%',
            top:'12%',
            bottom:'0%',
            containLabel:true,},
        props.grid,);const XSplitLine =mergeConfig({
            show:false,
            lineStyle:{
                type:'dashed',
                width:1,},},
        props.XSplitLine,);// 纵坐标分割线配置const YSplitLine =mergeConfig({// 是否显示// show: false,
            show:true,// 样式
            lineStyle:{
                color:'#13263e',
                type:'solid',
                width:1,},},
        props.YSplitLine,);const XAxisTick =mergeConfig({
            show:false,
            length:5,
            inside:true,
            alignWithLabel:true,
            lineStyle:{
                type:'solid',
                width:1,},},
        props.XAxisTick,);const YAxisTick =mergeConfig({
            show:true,
            length:5,
            inside:true,
            alignWithLabel:true,
            lineStyle:{
                color:'#13263e',
                type:'solid',
                width:1,},},
        props.YAxisTick,);let option: echarts.EChartsCoreOption ={
        title,
        tooltip:{
            show:false,// 指示器提示的坐标轴
            trigger:'axis',// 阴影提示器
            axisPointer:{
                type:'shadow',
                shadowStyle:{
                    shadowColor:'#2e3e51',// 设置阴影的颜色},},formatter:function(params:any){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;}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)'],},});let option =initOption();let container: HTMLElement |null=null;let myChart: echarts.ECharts |null=null;constrenderChart=(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,(newVal, oldVal)=>{let notMerge =true;
        option =initOption();renderChart(notMerge);},{
        deep:true,},);functionexportImg(){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>

方式2: 象型柱图(type: “pictorialBar”)

echarts象型柱图的官网配置项点这里, 参考的案例在这里, 象型柱图可以单柱可以双柱
封装成组件的完整代码如下:

<template></template><script setup lang="ts">import{ nextTick, watch }from"vue";import echarts from"@/assets/ts/echarts";import{ LegendComponent }from"echarts/components";
echarts.use([LegendComponent]);// 合并配置方法functionmergeConfig(defaultConfig: object, config: object){return Object.assign(defaultConfig, config);}functioninitOption(): echarts.EChartsCoreOption {// 此时 使用组件只需要要将  zzx1的数据和 wgx1 的数据传递到子组件// 第一个柱子的值const zzx1 = props.series[0].data;// 实际值// 第二个柱子的值const wgx1 = props.series[1].data;// 变量: 改变每个柱子的大小, 后期可将其设置为动态的?const barWidth =30;const series =[// (0)第一个柱子 中间的正方形{
      type:"pictorialBar",// 象型柱状symbol:"diamond",

      symbolSize:[barWidth,5],// 调整大小// symbolOffset: [-13, -3], // 图形相对于原本位置的偏移
      symbolOffset:["-55%",-3],// 图形相对于原本位置的偏移
      symbolPosition:"end",
      z:12,
      color:"#2584e0",
      data: zzx1,},// (1)第二个柱子中间的正方形{
      type:"pictorialBar",symbol:"diamond",
      symbolSize:[barWidth,8],// symbolOffset: [13, -3],
      symbolOffset:["55%",-3],
      symbolPosition:"end",
      z:12,
      color:"#07fdd3",
      data: wgx1,},//  (2)第一个柱子 底部的正方形{
      type:"pictorialBar",symbol:"diamond",
      symbolSize:[barWidth,5],// symbolOffset: [-13, 3],
      symbolOffset:["-55%",3],
      z:12,
      color:"#355ba8",
      data: zzx1,},// (3)第二个柱子 底部的正方形{
      name:"",
      type:"pictorialBar",symbol:"diamond",
      symbolSize:[barWidth,5],// symbolOffset: [13, 3],
      symbolOffset:["55%",3],
      color:"#2095a3",
      z:12,
      data: wgx1,},// (4)一个柱子, 下方有颜色填充的的柱子{
      name: props.nameOne,
      type:"bar",
      barWidth: barWidth,
      barGap:"10%",// zlevel: 2,
      stack:"1",
      itemStyle:{
        opacity:0.7,
        color:newecharts.graphic.LinearGradient(0,0,1,0,[{
            offset:0.5,
            color:"rgba(44, 97, 188,0.7)",// color: '#2c61bc',},{
            offset:0.5,
            color:"#2584e0",},{
            offset:1,
            color:"#214a87",},]),// barBorderRadius: 0,
        borderRadius:0,},// 是否在每个柱子显示 相应的值
      label:{
        show:true,

        position:["0","-25"],
        color:"#005dd9",
        fontSize:14,
        fontWeight:'bold'},
      data: zzx1,},// (5)第二个柱子, 下方有颜色填充的的柱子{
      name: props.nameTow,
      type:"bar",
      stack:"2",
      barWidth: barWidth,
      itemStyle:{
        opacity:0.7,
        color:newecharts.graphic.LinearGradient(0,0,1,0,[{
            offset:0.5,
            color:"rgba(15, 182, 182,0.7)",},{
            offset:0.5,
            color:"#0ccec7",},{
            offset:1,
            color:"#0bddd0",},]),// barBorderRadius: 0,
        borderRadius:0,},// 是否在每个柱子显示 相应的值
      label:{
        show:true,
        position:["0","-25"],
        color:"#06e6f6",
        fontSize:14,
        fontWeight:'bold'},
      data: wgx1,},];// title 配置const title =mergeConfig({// 是否显示
      show:true,// title 文本
      text:"",
      top:0,
      left:"left",// 文字样式
      textStyle:{
        color:"#fff",
        fontSize:16,},},
    props.title
  );// 横坐标轴线配置const XAxisLine =mergeConfig({// 是否显示
      show:true,// show: false,// 样式
      lineStyle:{// color: "rgba(46, 60, 87)",
        type:"solid",
        width:1,},},
    props.XAxisLine
  );// 纵坐标轴线配置const YAxisLine =mergeConfig({// 是否显示// show: true,
      show:false,// 样式
      lineStyle:{// 是否显示
        show:true,// 样式
        lineStyle:{
          color:"#fff",
          type:"solid",
          width:1,},},},
    props.YAxisLine
  );// 横坐标分割线配置const XSplitLine =mergeConfig({// 是否显示
      show:false,// 样式
      lineStyle:{
        color:"#fff",
        type:"dotted",
        width:1,},},
    props.XSplitLine
  );// 纵坐标分割线配置const YSplitLine =mergeConfig({// 是否显示
      show:true,// 样式
      lineStyle:{
        color:"rgba(46, 59, 86)",
        type:'dashed',// type: "solid",
        width:1,},},
    props.YSplitLine
  );// 横坐标刻度配置const XAxisTick =mergeConfig({// 是否显示
      show:false,// 刻度长度
      length:5,// 是否朝内
      inside:true,// 刻度是否居中
      alignWithLabel:true,// 样式
      lineStyle:{
        color:"#fff",
        type:"solid",
        width:1,},},
    props.XAxisTick
  );// 纵坐标刻度配置const YAxisTick =mergeConfig({// 是否显示
      show:false,// 刻度长度
      length:5,// 是否朝内
      inside:true,// 刻度是否居中
      alignWithLabel:true,
      color:"#fff",// 样式
      lineStyle:{
        color:"#fff",
        type:"solid",
        width:1,},},
    props.YAxisTick
  );// 图例标记配置const legend =mergeConfig({
      show:true,
      right:"0",
      top:"0",
      icon:"rect",
      itemHeight:10,
      itemWidth:10,
      textStyle:{
        color:"#fff",},// 取消默认点击事件
      selectedMode:false,// 距离
      itemGap:50,},
    props.legend
  );// 指示器:const tooltip ={
    show:false,
    trigger:"axis",
    axisPointer:{
      type:"shadow",},formatter:function(e:any){// console.log(e);var str =
        e[4].axisValue +"<br>"+"<span style='display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:"+
        e[4].color.colorStops[0].color +";'></span>"+""+
        e[4].seriesName +" : "+
        e[4].value +"<br>"+"<span style='display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:"+
        e[5].color.colorStops[0].color +";'></span>"+""+
        e[5].seriesName +" : "+
        e[5].value;return str;},// 提示框背景颜色
    backgroundColor:"#122843",// 提示框边框颜色
    borderColor:"#42D1F1",// 提示框文本样式
    textStyle:{
      color:"#fff",},};// 汇总配置let option: echarts.EChartsCoreOption ={
    title,
    tooltip,
    legend,
    grid:{
      top:"12%",
      left:"2%",
      right:"2%",
      bottom:"5%",// height: "85%",
      containLabel:true,},
    xAxis:{
      type:"category",
      boundaryGap:true,
      data: props.xAxisData,
      axisLine: XAxisLine,
      splitLine: XSplitLine,
      axisTick: XAxisTick,
      axisLabel:{// textStyle: {
        color:"#fff",
        fontSize:16// },},},
    yAxis:{
      type:"value",// 单位
      name: props.yUnit,
      axisLine: YAxisLine,
      splitLine: YSplitLine,
      axisTick: YAxisTick,
      axisLabel:{// textStyle: {
        color:"#fff",
        fontSize:16// },},
      
      min:0,// max: props.max,},
    series,};// 合并配置生成最终配置
  option = Object.assign(option, props.config);return option;}// propsconst props =defineProps({// 父容器ID
  pid:{
    type: String,
    required:true,},
  title:{
    type: Object,default:{},},// 数据
  series:{// type: Array as () => Array<BarSeriesOption>,
    type:Arrayas()=>{ data:number[]}[],
    required:true,},// 横坐标
  xAxisData:{
    type:Array,
    required:true,},// 图例标记
  legend:{
    type: Object,default:{},},// 横坐标轴线
  XAxisLine:{
    type: Object,default:{},},// 纵坐标轴线
  YAxisLine:{
    type: Object,default:{},},// y轴单位
  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:{},},// 最值// max: {//     type: Number,//     // requird: true,//     default: 5000,// },
  nameOne:{
    type: String,default:"昨日总量",},
  nameTow:{
    type: String,default:"今日总量",},});// optionlet option =initOption();// chart 容器let container: HTMLElement |null=null;// chart 实例let myChart: echarts.ECharts |null=null;// 渲染方法constrenderChart=()=>{if(!myChart) myChart = echarts.init(container as HTMLElement);
  myChart.setOption(option);};// DOM加载后渲染 chartnextTick(()=>{// 获取容器
  container = document.querySelector("#"+ props.pid)as HTMLElement;// 渲染 chartrenderChart();// 自适应 chart// useResizeChart(container, myChart as echarts.ECharts);});// 监听 props 变化watch(()=> props,()=>{// 更新 option
    option =initOption();// 重新渲染chartrenderChart();},{
    deep:true,});// 导出为图片functionexportImg(){// 生成 base64 图片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();}// 暴露出 chart 图片导出方法,父组件可以通过实例调用defineExpose({
  exportImg,});</script><style lang="scss" scoped></style>

本文转载自: https://blog.csdn.net/weixin_69773376/article/details/128199545
版权归原作者 蜗牛升值记 所有, 如有侵权,请联系我们删除。

“echarts实现3d柱状图的两种方式”的评论:

还没有评论