echarts实现立体柱状图

实现效果图如下:
在这里插入图片描述
上面除了立体图之外还增加了背景图。注意,可以发现这个图的右下角是是和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)为起点。
欢迎评论。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于C#的窗体阴影效果方案 - 开源研究系列文章

最近在研究C#的Winform窗体的效果&#xff0c;上次介绍了窗体动画效果的博文( 基于C#的无边框窗体动画效果的完美解决方案 - 开源研究系列文章 )&#xff0c;这次将窗体阴影效果的方案进行一个介绍。 找了一下度娘&#xff0c;具体窗体阴影效果就两种方法&#xff1a;直接绘制和…

前端Vue入门-day08-vant组件库

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 vant 组件库 安装 导入 全部导入 按需导入 浏览器配饰 Viewport 布局 Rem 布局适配 vant 组件库 …

ssh安全远程管理

目录 1、什么是ssh 2、ssh登陆 3、ssh文件传输 1、什么是ssh ssh是 Secure Shell 的缩写&#xff0c;是一个建立在应用层上的安全远程管理协议。ssh 是目前较为可靠的传输协议&#xff0c;专为远程登录会话和其他网络服务提供安全性。利用ssh 协议可以有效防止远程管理过程中…

MySQL常见问题处理(三)

MySQL 常见问题解决 夕阳留恋的不是黄昏&#xff0c;而是朝阳 上一章简单介绍了MySQL数据库安装(二), 如果没有看过, 请观看上一章 一. root 用户密码忘记&#xff0c;进行重置操作 复制内容来源链接: https://blog.csdn.net/weixin_48927364/article/details/123556927 一.…

谷粒商城第八天-商品服务之品牌管理的整体实现(直接使用逆向生成的代码;含oss文件上传)

目录 一、总述 二、前端部分 2.1 创建好品牌管理菜单 2.2 复制组件 ​编辑2.3 复制api ​​​编辑 2.4 查看效果 ​编辑2.5 需要优化的地方 2.6 具体优化实现 2.6.1 优化一&#xff1a;将表格的状态列&#xff08;这里是是否显示列&#xff09;修改为开关&#xff…

JS解析JSON

在 JavaScript 中解析 JSON 数据 在 JavaScript 中&#xff0c;您可以使用 JSON.parse() 方法来解析 JSON 数据&#xff0c;示例代码如下&#xff1a; var json {"course": {"name": "JavaScript","author": "http://c.bianch…

【2023.8】docker一键部署wvp-GB28181-pro和ZLMediaKit过程全记录

安装docker 使用的操作系统是ubuntu20.04 如何在 Ubuntu 20.04 上安装和使用 Docker https://developer.aliyun.com/article/762674 docker拉取配置好的ZLMediaKIt和wvp-GB28181-pro docker pull 648540858/wvp_pro第一次运行 docker一键运行ZLMediaKIt和wvp-GB28181-pro …

Linux的基本指令(2)

指令1&#xff1a;man 作用&#xff1a;可以查询linux指令语法内容。 格式&#xff1a; man 指令 安装man指令&#xff1a; yum install -y man-pages 例如&#xff1a; 查询 指令 ls 的语法内容。 man ls 查询 fork 指令的语法内容。 man fork 在man中存在9个手册&…

【设计模式——学习笔记】23种设计模式——观察者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入原始方案实现实现问题分析 介绍基础介绍登场角色 案例实现案例一类图实现分析 案例二类图实现 观察者模式在JDK源码的应用总结文章说明 案例引入 有一个天气预报项目&#xff0c;需求如下&#xff1a; 气象站可以将每天测量到的温度、湿度、气压等等以公告的…

JMeter(二十四)、使用吞吐量控制器实现不同的用户操纵不同的业务

一、需求 需求&#xff1a;博客系统&#xff0c;模拟用户真实行为&#xff0c;80%的用户阅读文章&#xff0c;20%的用户创建文章&#xff0c;创建文章的用户随机的删除或者修改文章。 二、脚本实现 80%的用户查看文章 20%用户创建文章 根据post_id是否能整除2&#xff0c;决…

【vue】 el-table解决分页不能筛选全部数据的问题

前言 最近开发前端项目表格的时候&#xff0c;使用的是el-table&#xff0c;用到了对应的筛选功能&#xff0c;如下图所示 但发现实际只能筛选当前页&#xff0c;通过百度查找相关文章&#xff0c;发现原因是把筛选条件定义在列上&#xff0c;解决方法&#xff1a;所以我们把f…

使用 Simulink 进行 STM32 编程

目录 介绍 所需材料 步骤 1&#xff1a;在MATLAB中设置STM32-MAT软件路径步骤 2&#xff1a;在STM32CubeMX中创建一个项目步骤 3&#xff1a;配置时钟和 GPIO 引脚步骤 4&#xff1a;项目经理并生成代码步骤 5&#xff1a;在 Simulink 中创建模型步骤 6&#xff1a;在模型中插…

Systemui的介绍以及与普通应用的差异

一.SystemUI的介绍 简介 SystemUI是Android操作系统的一个关键组件&#xff0c;主要负责管理和提供用户界面的核心元素&#xff0c;如状态栏、导航栏和锁屏界面等。从下面两点出发了解SystemUI的特性&#xff1a; 一下就是systemui的部分界面&#xff0c;还包括锁屏界面&…

git merge 和rebase区别

Merge the incoming changes into the current branch 找到两个分支的祖先 commit&#xff0c;然后将公共分支最新版合并到自己的分支&#xff0c;形成一个新的 commit 提交&#xff0c;用图表示如下。 Rebase the current branch on top of the incoming Rebase 则是重新基于…

CSS学习记录(基础笔记)

CSS简介: CSS 指的是层叠样式表* (Cascading Style Sheets)&#xff0c;主要用于设置HTML页面的文字内容&#xff08;字体、大小、对齐方式&#xff09;&#xff0c;图片的外形&#xff08;边框&#xff09; CSS 描述了如何在屏幕、纸张或其他媒体上显示 HTML 元素 CSS 节省…

从SQL注入绕过最新安全狗WAF中学习fuzz

前言 SQL注入并不是很精通&#xff0c;通过实战绕过WAF来进行加强SQL注入能力&#xff0c;希望对正在学习的师傅能有一丝帮助。 安装 安装前言 我是本地搭建的环境进行测试的 环境是windows11phpstudy2018sqli-labs phpstudy的安装我不再复述&#xff0c;这里简单说一下安全…

vue3数组V-for中动态生成$refs

vue3数组V-for中动态生成$refs 在项目实际需求中&#xff0c;可能会遇到使用数组动态生成$refs,根据官方参考&#xff0c;采用了以下方式实现 <template><div class"content"><ul v-for"(item, index) in editableTabs" :key"item.n…

SolidUI社区-从开源社区角度思考苹果下架多款ChatGPT应用

文章目录 背景下架背景下架原因趋势SolidUI社区的未来规划结语如果成为贡献者 背景 随着文本生成图像的语言模型兴起&#xff0c;SolidUI想帮人们快速构建可视化工具&#xff0c;可视化内容包括2D,3D,3D场景&#xff0c;从而快速构三维数据演示场景。SolidUI 是一个创新的项目…

斯坦福大学提出在类别层级对多零件多关节三维拼装新方法

来源&#xff1a;投稿 作者&#xff1a;橡皮 编辑&#xff1a;学姐 paper&#xff1a;https://arxiv.org/pdf/2303.06163.pdf 背景&#xff1a; 形状装配通过排列一组简单或基本的零件几何图形来组成复杂的形状几何图形。许多重要的任务和应用都依赖于形状装配算法。 计算机…

你是否好奇交流充电桩主板的安装维度?

你是否好奇交流充电桩主板的安装维度?安装环境、要求和方式&#xff0c;将影响充电桩的可靠性和安全性。 交流充电桩主板的安装环境至关重要&#xff0c;设备需要安装在室外&#xff0c;因此应选择防水、防火、耐候、耐腐蚀的材料。同时&#xff0c;安装要求具有良好的接地&am…