echarts实现立体柱状图

news2024/9/22 5:34:01

实现效果图如下:
在这里插入图片描述
上面除了立体图之外还增加了背景图。注意,可以发现这个图的右下角是是和x轴平齐的,如果右下角也要折角,可以根据代码修改下描点的点位就可以了。
完整代码如下:

<template>
  <div id="bar-chart" ref="barChartRef"></div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';
import * as echarts from 'echarts'
const barChartRef = ref()
let barChart = null
let options = {}
const data = ref([])

const imgSrc =
    'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAI6CAYAAACw4c+4AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQyIDc5LjE2MDkyNCwgMjAxNy8wNy8xMy0wMTowNjozOSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0NWI1MDY3Mi1kMzI4LTNmNDQtOTA2NC0xNDhlOGFlNWUzYmIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzI5MUNFMEQyOUJCMTFFRTg4ODhBOEM3M0UzMDIwQUMiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzI5MUNFMEMyOUJCMTFFRTg4ODhBOEM3M0UzMDIwQUMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTggKFdpbmRvd3MpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NWExOTdhNTctNDIzYi01MDQyLThkMGMtZjMxZTIwNWRlYTViIiBzdFJlZjpkb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6NjE2MTU1ZmUtY2M3Ni1mNTQ3LThlNzItMmZkOTcxZmU0Mjk5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+hTdV3gAABDNJREFUeNrs1iESQAAURVG+JFqCGV0QVNuwZEGwEkk1qhmSH5Tz6m0vnbLtp7m4bRz6Zlm3vXiZ9mzhhFwLJ+RaOCHXwgm5Vh1n3Tnoewsn5Fo4AWMwBmMwxkEYgzEYgzEOwhiMwRiMcRDGYAzGYIyDMAZjMAZjNIzBGIzBGA1jMAZjMEbDGIzBGIzRMAZjMAZjNIzBGIzBGA1jMAZjMAZjHIQxGIMxGOMgjMEYjMEYB2EMxmAMxjgIYzAGYzDGQRiDMRiDMRrGYAzGYIyGMRiDMRijYQzGYAzGaBiDMRiDMRrGYAzGYAzGOAFjMAZjMMZBGIMxGIMxDsIYjMEYjHEQxmAMxmCMgzAGYzAGYzSMwRiMwRgNYzAGYzBGwxiMwRiM0TAGYzAGYzSMwRiMwRgNYzAGYzAGYzAGYzAGYzDGQRiDMRiDMQ7CGIzBGIxxEMZgDMZgjIMwBmMwBmM0jMEYjMEYDWMwBmMwRsMYjMEYjNEwBmMwBmM0jMEYjMEYjHECxmAMxmCMgzAGYzAGYxyEMRiDMRjjIIzBGIzBGAdhDMZgDMZoGIMxGIMxGsZgDMZgjIYxGIMxGKNhDMZgDMZoGIMxGIMxGsZgDMZgDMY4CGMwBmMwxkEYgzEYgzEOwhiMwRiMcRDGYAzGYIyDMAZjMAZjNIzBGIzBGA1jMAZjMEbDGIzBGIzRMAZjMAZjNIzBGIzBGIxxAsZgDMZgjIMwBmMwBmMchDEYgzEY4yCMwRiMwRgHYQzGYAzGOAhjMAZjMEbDGIzBGIzRMAZjMAZjNIzBGIzBGA1jMAZjMEbDGIzBGIzBGAdhDMZgDMY4CGMwBmMwxkEYgzEYgzEOwhiMwRiMcRDGYAzGYIyGMRiDMRijYQzGYAzGaBiDMRiDMRrGYAzGYIyGMRiDMRiDMU7AGIzBGIxxEMZgDMZgjIMwBmMwBmMchDEYgzEY4yCMwRiMwRgNYzAGYzBGwxiMwRiM0TAGYzAGYzSMwRiMwRgNYzAGYzBGwxiMwRiMwRgHYQzGYAzGOAhjMAZjMMZBGIMxGIMxDsIYjMEYjHEQxmAMxmCMhjEYgzEYo2EMxmAMxmgYgzEYgzEaxmAMxmCMhjEYgzEYgzFOwBiMwRiMcRDGYAzGYIyDMAZjMAZjHIQxGIMxGOMgjMEYjMEYDWMwBmMwRsMYjMEYjNEwBmMwBmM0jMEYjMEYDWMwBmMwRsMYjMEYjMEYB2EMxmAMxjgIYzAGYzDGQRiDMRiDMQ7CGIzBGIxxEMZgDMZgjIYxGIMxGKNhDMZgDMZoGIMxGIMxGsZgDMZgjIYxGIMxGIMxGIMxGIMxGOMgjMEYjMEYB2EMxmAMxjgIYzAGYzDGQRiDMRiDMRrGYAzGYIyGMRiDMRijYQzGYAzGaBiDMRiDMRrGYAzGYIyGMRiDMRiDMQ7CmP/aJcAAaiRuLcLv/0cAAAAASUVORK5CYII='
const patternImg = new Image()
patternImg.src = imgSrc

const initChart = async () => {
  if (barChart) {
    barChart.dispose()
    barChart = null
  }

  await nextTick()
  barChart = echarts.init(barChartRef.value)

  // 数据
  data.value = [
    { name: '西瓜', value: 10 },
    { name: '草莓', value: 20 },
    { name: '苹果', value: 15 },
    { name: '菠萝', value: 28 },
    { name: '葡萄', value: 13 }
  ]

  const xData = data.value.map(item => item.name) // x轴的label数据
  const yData = data.value.map(item => item.value) // series中data的数据

  options = {
    tooltip: {
      trigger: 'axis',
    },
    grid: { 
      top: 20,
      left: 30,
      right: 10,
      bottom: 30
    },
    xAxis: {
      type: 'category',
      data: xData,
      // 坐标轴线
      axisLine: {
        show: true,
        lineStyle: {
          color: '#FFFFFF',
          opacity: 0.4,
          width: 1,
          type: 'solid'
        }
      },
      // 坐标轴刻度
      axisTick: {
        show: false
      },
      // 坐标轴刻度标签
      axisLabel: {
        show: true,
        color: '#FFFFFF',
        fontWeight: 400,
        fontSize: 12,
        margin: 12
      },
      // 分隔线
      splitLine: {
        show: true,
        lineStyle: {
          color: '#FFFFFF',
          width: 1,
          opacity: 0.15,
          type: 'dashed'
        }
      }
    },
    yAxis: {
      type: 'value',
      // max: 1000,
      // 坐标轴名称和样式
      name: '',
      minInterval: 1,
      nameTextStyle: {
        padding: [0, 8, 0, 0],
        fontSize: 12,
        color: '#8F9297',
        fontWeight: 400
      },
      // 坐标轴线
      axisLine: {
        show: true,
        lineStyle: {
          color: '#FFFFFF',
          opacity: 0.14,
          width: 1
        }
      },
      // 坐标轴刻度
      axisTick: {
        show: false
      },
      // 坐标轴刻度标签
      axisLabel: {
        show: true,
        color: '#8F9297',
        fontSize: 12,
        fontWeight: 400,
      },
      // 分隔线
      splitLine: {
        show: true,
        lineStyle: {
          color: '#FFFFFF',
          width: 1,
          opacity: 0.15,
          type: 'dashed'
        }
      }
    },
    series: [
      {
        data: yData,
        type: 'custom',
        renderItem: function (params, api) {
          return getRenderItem(params, api)
        },
        itemStyle: {
          color: {
            image: patternImg,
            repeat: 'repeat'
          }
        }
      }
    ]
  }
  // 定义柱状图左侧图形元素
  const leftRect = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0,
      width: 21, //柱状图宽
    },
    buildPath: function (ctx, shape) {
      const api = shape.api
      const xAxisPoint = api.coord([shape.xValue, 0]) // 根据列表中index的值转化为坐标点
      
      const p0 = [shape.x - shape.width, shape.y]  // 左上点位
      const p1 = [shape.x - shape.width, xAxisPoint[1]] // 左下点位
      const p2 = [shape.x, xAxisPoint[1]] // 右下点位
      const p3 = [shape.x, shape.y] // 右上点位
      
      ctx.moveTo(p0[0], p0[1])
      ctx.lineTo(p1[0], p1[1])
      ctx.lineTo(p2[0], p2[1])
      ctx.lineTo(p3[0], p3[1])
      ctx.lineTo(p0[0], p0[1])
      ctx.closePath()
    }
  })
  // 定义柱状图右侧图形元素
  const rightRect = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0,
      width: 11,
      zWidth: 11,
      zHeight: 11
    },
    buildPath: function (ctx, shape) {
      const api = shape.api
      const xAxisPoint = api.coord([shape.xValue, 0]) // 坐标点
      const p0 = [shape.x, shape.y] // 左上点位
      const p1 = [shape.x, xAxisPoint[1]] // 左下点位
      const p2 = [shape.x + shape.width, xAxisPoint[1]] // 右下点位
      const p3 = [shape.x + shape.width, shape.y - shape.zHeight] // 右上点位
      
      ctx.moveTo(p0[0], p0[1])
      ctx.lineTo(p1[0], p1[1])
      ctx.lineTo(p2[0], p2[1])
      ctx.lineTo(p3[0], p3[1])
      ctx.lineTo(p0[0], p0[1])
      ctx.closePath()
    }
  })
    
  // 定义柱状图顶部图形元素
  const topRect = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0,
      width: 21,
      zWidth: 11,
      zHeight: 11
    },
    buildPath: function (ctx, shape) {
      const p0 = [shape.x - shape.width + shape.zWidth, shape.y - shape.zHeight] // 左上点位
      const p1 = [shape.x - shape.width, shape.y] // 左下点位
      const p2 = [shape.x, shape.y] // 右下点位
      const p3 = [shape.x + shape.zWidth, shape.y - shape.zHeight] // 右上点位
      
      ctx.moveTo(p0[0], p0[1])
      ctx.lineTo(p1[0], p1[1])
      ctx.lineTo(p2[0], p2[1])
      ctx.lineTo(p3[0], p3[1])
      ctx.lineTo(p0[0], p0[1])
      ctx.closePath()
    }
  })
  // 定义柱状图背景图形元素
  const bgRect = echarts.graphic.extendShape({
    shape: {
      x: 0,
      y: 0,
      width: 32,
      zWidth: 11,
      zHeight: 0
    },
    buildPath: function (ctx, shape) {
      const api = shape.api
      const xAxisPoint = api.coord([shape.xValue, 0]) // 坐标点
      const p0 = [shape.x - shape.width + shape.zWidth, 20] // 左上点位 根据grid.top的位置得到高
      const p1 = [shape.x - shape.width + shape.zWidth, xAxisPoint[1]] // 左下点位
      const p2 = [shape.x + shape.zWidth, xAxisPoint[1]] // 右下点位
      const p3 = [shape.x + shape.zWidth, 20] // 右上点位 根据grid.top的位置得到高
      
      ctx.moveTo(p0[0], p0[1])
      ctx.lineTo(p1[0], p1[1])
      ctx.lineTo(p2[0], p2[1])
      ctx.lineTo(p3[0], p3[1])
      ctx.lineTo(p0[0], p0[1])
      ctx.closePath()
    }
  })

  // 注册图形元素
  echarts.graphic.registerShape('leftRect', leftRect)
  echarts.graphic.registerShape('rightRect', rightRect)
  echarts.graphic.registerShape('topRect', topRect)
  echarts.graphic.registerShape('bgRect', bgRect)

  // 渲染图形
  function getRenderItem(params, api) {
    const location = api.coord([api.value(0), api.value(1)])  // 根据 data的index值和data转化为坐标像数值
    return {
      type: 'group',
      children: [
        {
          type: 'bgRect',
          shape: {
            api,
            xValue: api.value(0),
            yValue: api.value(1),
            x: location[0],
            y: location[1]
          },
          style: api.style()
        },
        {
          type: 'leftRect',
          shape: {
            api,
            xValue: api.value(0), // index值
            yValue: api.value(1), // data值
            x: location[0], // x像素
            y: location[1] // y像素
          },
          style: {
            fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 1, color: 'rgba(57,160,247,0)' },
              { offset: 0, color: 'rgba(57, 159, 246,1)' }
            ])
          }
        },
        {
          type: 'rightRect',
          shape: {
            api,
            xValue: api.value(0),
            yValue: api.value(1),
            x: location[0],
            y: location[1]
          },
          style: {
            fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 1, color: 'rgba(32,130,213,0)' },
              { offset: 0, color: 'rgba(32,130,213,1)' }
            ])
          }
        },
        {
          type: 'topRect',
          shape: {
            api,
            xValue: api.value(0),
            yValue: api.value(1),
            x: location[0],
            y: location[1]
          },
          style: {
            fill: '#3392E3'
          }
        }
      ]
    }
  }
  options && barChart.setOption(options, true)
}

onMounted(() => {
  initChart()
})
</script>

<style lang="scss" scoped>
#bar-chart {
  width: 500px;
  height: 400px;
  background-color: #142331;
}
</style>

这里最关键的实现思路就是把各个点位计算出来,然后连线。如果实在不懂这个意思的话建议是了解下canvas绘画或者仔细阅读下echarts中custom的自定义图表。最简单就是打印一下getRenderItem(params, api)中的参数代表什么意思。canvas的图都是从左上角(0,0)为起点。
欢迎评论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/840207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从特斯拉FSD v11.4.6,看FSD入华

从特斯拉FSD v11.4.6&#xff0c;看FSD入华 1. 芝加哥城区a. 亮点b. 问题 2. 小镇中心a. 亮点b. 问题 3. FSD入华a. 技术路线b. 场景 4. 参考视频 FSD最近更新了v11.4.6&#xff0c;本文根据2个FSD城区测试视频&#xff0c;一起看一下有哪些亮点和问题。 FSD入华的消息也甚嚣尘…

HTML5中Canvas学习笔记:Canvas

目录 一、HTML中Canvas画图strokeStyle 和 fillStyle 的区别是什么&#xff1f; 二、如何设置一幅canvas图中某个颜色透明&#xff1f; 三、H5 canvas中strokeRect参数如果是小数&#xff0c;如何处理&#xff1f; 四、H5 Canvas中如何画圆角矩形框&#xff1f; 一、HTML中…

python字符串输入输出与注解

目录 数据输入 前言 数据输出 字符串 字符串的三种定义方法 引号嵌套 字符串的拼接 字符串格式化 拼接字符串缺点 python常用的格式符号 格式化的精度控制 字符串快速格式化 快速格式化特点 对表达式进行格式化 具体案例 字符串的大小比较 字符串比较方式 变…

分类预测 | MATLAB实现WOA鲸鱼算法同步优化特征选择结合支持向量机分类预测

分类预测 | MATLAB实现WOA鲸鱼算法同步优化特征选择结合支持向量机分类预测 目录 分类预测 | MATLAB实现WOA鲸鱼算法同步优化特征选择结合支持向量机分类预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 MATLAB实现WOA鲸鱼算法同步优化特征选择结合支持向量机分类预测…

DASCTF 2023 0X401七月暑期挑战赛 Web方向 EzFlask ez_cms MyPicDisk 详细题解wp

EzFlask 源码直接给了 CtrlU查看带缩进的源码 import uuidfrom flask import Flask, request, session # 导入黑名单列表 from secret import black_list import jsonapp Flask(__name__) # 为 Flask 应用设置一个随机的 secret_key app.secret_key str(uuid.uuid4())# 检查…

epoll、poll、select的原理和区别

select&#xff0c;poll&#xff0c;epoll都是IO多路复用的机制。I/O多路复用就是通过一种机制&#xff0c;一个进程可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读就绪或者写就绪&#xff09;&#xff0c;能够通知程序进行相应的读写操作。但select&a…

Android 实现账号诊断动画效果,逐条检测对应的项目

Dialog中的项目 逐条检测效果&#xff1a; 依赖库&#xff1a; implementation com.github.li-xiaojun:XPopup:2.9.19 implementation com.blankj:utilcodex:1.31.1 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.101、item_account_check.xml <…

【C语言】静态关键字static的用法(详解)

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;C语言初阶 ✨其他专栏&#xff1a;代码小游戏 &#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论…

I.MX6ULL_Linux_驱动篇(44)linux MISC驱动

MISC 驱动也叫做杂项驱动&#xff0c;也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动&#xff0c;通常嵌套在 platform 总线驱动中&#xff0c;实现复杂的驱动&#xff0c;本章我们就来学习一下 MISC 驱动的编写…

恺英网络宣布:与华为鸿蒙系统展开合作,将开发多款手游

8月5日消息&#xff0c;恺英网络宣布旗下子公司盛和网络参加了华为开发者大会&#xff08;HDC.Together&#xff09;游戏服务论坛&#xff0c;并在华为鸿蒙生态游戏先锋合作启动仪式上进行了亮相。恺英网络表示&#xff0c;将逐步在HarmonyOS上开发多款游戏&#xff0c;利用Har…

【C++】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置)

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…

ffmpeg-ffplay代码架构简述

全局变量 /* Minimum SDL audio buffer size, in samples. */ // 最小音频缓冲 #define SDL_AUDIO_MIN_BUFFER_SIZE 512 /* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */ // 计算实际音频缓冲大小&#xff0c;并不需要太频繁…

c语言基础知识帮助理解(详解数组)

前面梳理完函数和递归的知识后&#xff0c;来进行数组知识的梳理 对函数有疑惑的同学&#xff0c;可以看我之前的文章&#xff1a;c语言基础知识帮助理解&#xff08;详解函数&#xff09;_总之就是非常唔姆的博客-CSDN博客 c语言基础知识帮助理解&#xff08;函数递归详解&am…

类的6个默认成员函数 构造函数

类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生…

ruoyi-cloud-notes01

1、Maven中的dependencyManagement Maven中的dependencyManagement元素提供了一种管理依赖版本号的方式。在dependencyManagement元素中声明所依赖的jar包的版本号等信息&#xff0c;那么所有子项目再次引入此依赖jar包时则无需显式的列出版本号。Maven会沿着父子层级向上寻找…

HCIP MPLS总结

一、MPLS--多协议标签交换 多协议&#xff1a;可以基于多种不同的3层协议来生成2.5层的标签信息&#xff1b; 包交换&#xff1a;包为网络层的PDU&#xff0c;故包交换是基于IP地址进行数据转发&#xff1b;就是路由器的路由行为&#xff1b; 原始的包交换&#xff1a;数据包…

STM32 CubeMX USB_CDC(USB_转串口)

STM32 CubeMX STM32 CubeMX 定时器&#xff08;普通模式和PWM模式&#xff09; STM32 CubeMX一、STM32 CubeMX 设置USB时钟设置USB使能UBS功能选择 二、代码部分添加代码实验效果 ![请添加图片描述](https://img-blog.csdnimg.cn/a7333bba478441ab950a66fc63f204fb.png)printf发…

分库分表概念、原理、拆分策略和实现技术讲解

文章目录 1.什么是分库分表2.分库分表拆分策略2.1 垂直拆分2.2 水平拆分 3.分库分表实现技术简介 1.什么是分库分表 分库分表的中心思想就是将数据分散存储&#xff0c;使得单一数据库/表的数据量变小来缓解单一数据库的性能问题&#xff0c;从而达到提升数据库性能的目的。 …

python中使用yt-dlp模块实现带进程条下载音视频

当代的互联网时代&#xff0c;视频内容的流行无疑是其中的重要组成部分。作为全球最大的视频分享平台&#xff0c;每天吸引着数以亿计的用户观看各种各样的视频内容。有时候&#xff0c;我们可能希望将某些喜欢的视频保存到本地进行观看&#xff0c;或者将它们用于其他用途。在…