如何让柱状图有3D的感觉,圆柱体的形状;如下图
这里就需要用到type: "pictorialBar", // 象形图形; 不废话,直接上代码
<template>
<div :id="id" :class="className" :style="{ height: height, width: width }" />
</template>
<script>
import echarts from "echarts";
import resize from "./mixins/resize";
export default {
mixins: [resize],
props: {
className: {
type: String,
default: "chartA",
},
id: {
type: String,
default: "chartA",
},
width: {
type: String,
default: "400px",
},
height: {
type: String,
default: "400px",
},
},
data() {
return {
chart: null,
};
},
mounted() {
this.initChart();
},
beforeDestroy() {
if (!this.chart) {
return;
}
this.chart.dispose();
this.chart = null;
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id));
// 测试
let xData = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"];
let yData = [];
for (let i = 0; i < 7; i++) {
let randomNumber = Math.floor(Math.random() * 900) + 100; // 生成三位随机数
yData.push(randomNumber);
}
this.chart.setOption({
backgroundColor: "#061326",
grid: {
top: "5%",
left: "5%",
bottom: "5%",
right: "5%",
containLabel: true,
},
tooltip: {
show: true,
},
animation: false,
xAxis: [
{
type: "category",
data: xData,
axisTick: {
alignWithLabel: true,
},
nameTextStyle: {
color: "#82b0ec",
},
axisLine: {
show: false,
lineStyle: {
color: "#82b0ec",
},
},
axisLabel: {
textStyle: {
color: "#fff",
},
margin: 30,
},
},
],
yAxis: [
{
// show: false,
type: "value",
axisLabel: {
textStyle: {
color: "#fff",
},
},
// 分割线
splitLine: {
lineStyle: {
color: "#0c2c5a",
},
},
// y轴线
axisLine: {
show: false,
lineStyle: {
color: "#0c2c5a",
},
},
},
],
series: [
{
name: "上部椭圆",
type: "pictorialBar",
symbolSize: [40, 12], // 图形的大小,可以用数组分开表示宽和高
symbolOffset: [0, -6], // 图形相对于原本位置的偏移, 左(负数)右,上(负数)下
symbolPosition: "end", // 图形的定位位置 'start':图形边缘与柱子开始的地方内切。'end':图形边缘与柱子结束的地方内切。'center':图形在柱子里居中。
// symbolRotate: 180, // 图形的旋转角度number
// symbolRepeat: "fixed", // 指定图形元素是否重复,
/*
值可为:
false/null/undefined:不重复,即每个数据值用一个图形元素表示。
true:使图形元素重复,即每个数据值用一组重复的图形元素表示。重复的次数依据 data 计算得到。
a number:使图形元素重复,即每个数据值用一组重复的图形元素表示。重复的次数是给定的定值。
'fixed':使图形元素重复,即每个数据值用一组重复的图形元素表示。重复的次数依据 symbolBoundingData 计算得到,即与 data 无关。这在此图形被用于做背景时有用。
*/
/*
其他属性:
symbolMargin :
图形的两边间隔(『两边』是指其数值轴方向的两边)。可以是绝对数值(如 20),或者百分比值(如 '-30%'),表示相对于自身尺寸 symbolSize 的百分比。只有当 symbolRepeat 被使用时有意义。
可以是正值,表示间隔大;也可以是负数。当 symbolRepeat 被使用时,负数时能使图形重叠。
symbolRepeatDirection:指定图形元素重复时,绘制的顺序。
这个属性在两种情况下有用处:
当 symbolMargin 设置为负值时,重复的图形会互相覆盖,这是可以使用 symbolRepeatDirection 来指定覆盖顺序。
当 animationDelay 或 animationDelayUpdate 被使用时,symbolRepeatDirection 指定了 index 顺序。
这个属性的值可以是:'start' 或 'end'。
symbolClip:是否剪裁图形。
false/null/undefined:图形本身表示数值大小。
true:图形被剪裁后剩余的部分表示数值大小。
symbolClip 常在这种场景下使用:同时表达『总值』和『当前数值』。在这种场景下,可以使用两个系列,一个系列是完整的图形,
当做『背景』来表达总数值,另一个系列是使用 symbolClip 进行剪裁过的图形,表达当前数值。
*/
z: 12, // 象形柱图组件的所有图形的z值。控制图形的前后顺序。z值小的图形会被z值大的图形覆盖。z相比zlevel优先级更低,而且不会创建新的 Canvas。
// "barWidth": "0",
label: {
// 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等。
normal: {
show: true,
position: "top", // 标签的位置。
/**
* 支持:top / left / right / bottom / inside / insideLeft / insideRight / insideTop
* / insideBottom / insideTopLeft / insideBottomLeft / insideTopRight / insideBottomRight
* 也可以用一个数组表示相对的百分比或者绝对像素值表示标签相对于图形包围盒左上角的位置。
* 绝对的像素值 position: [10, 10], 相对的百分比 position: ['50%', '50%']
*/
// "formatter": "{c}%"
fontSize: 16, // 标签大小
fontWeight: "bold",
color: "#34DCFF",
},
},
color: "#2DB1EF", // 图形颜色
data: yData,
},
{
name: "下部椭圆",
type: "pictorialBar", // 象形图形
symbolSize: [40, 10], // 椭圆,图形大小
symbolOffset: [0, 7], // 图形偏移
z: 12,
color: "#2DB1EF",
data: yData,
},
{
name: "下部内环",
type: "pictorialBar", // 象形图形
symbolSize: function (d) {
return d > 0 ? [50, 15] : [0, 0];
},
symbolOffset: [0, 12], // 偏移量
z: 10,
itemStyle: {
normal: {
color: "transparent",
borderColor: "#2EA9E5",
borderType: "solid",
borderWidth: 1,
},
},
data: yData,
},
{
name: "下部外环",
type: "pictorialBar",
symbolSize: [70, 20], // 椭圆大小
symbolOffset: [0, 18], // 偏移
z: 10,
itemStyle: {
normal: {
color: "transparent",
borderColor: "#19465D",
borderType: "solid",
borderWidth: 2,
},
},
data: yData, // 对应的每个数据下面配置圆环
},
{
type: "bar", // 真实的柱状图
barWidth: "40",
// barGap: "10%", // 不同系列的柱间距离,为百分比(如 '30%',表示柱子宽度的 30%)
/**
* 如果想要两个系列的柱子重叠,可以设置 barGap 为 '-100%'。这在用柱子做背景的时候有用。
在同一坐标系上,此属性会被多个 'bar' 系列共享。此属性应设置于此坐标系中最后一个 'bar' 系列上才会生效,并且是对此坐标系中所有 'bar' 系列生效。
*/
barCateGoryGap: "10%", // 同一系列的柱间距离,默认为类目间距的20%,可设固定值
/**
* 在同一坐标系上,此属性会被多个 'bar' 系列共享。此属性应设置于此坐标系中最后一个 'bar' 系列上才会生效,并且是对此坐标系中所有 'bar' 系列生效。
*/
//图形样式
itemStyle: {
normal: {
// 设置过渡颜色
color: new echarts.graphic.LinearGradient(0, 0, 0, 0.7, [
{
offset: 0,
color: "#38B2E6",
},
{
offset: 1,
color: "#0B3147",
},
]),
opacity: 0.8,
},
},
data: yData,
},
],
});
},
},
};
</script>
resize.js 监听浏览器放缩,重绘图形
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null
}
},
mounted() {
this.initListener()
},
activated() {
if (!this.$_resizeHandler) {
// avoid duplication init
this.initListener()
}
// when keep-alive chart activated, auto resize
this.resize()
},
beforeDestroy() {
this.destroyListener()
},
deactivated() {
this.destroyListener()
},
methods: {
// use $_ for mixins properties
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
resize() {
const { chart } = this
chart && chart.resize()
}
}
}
debounce 防抖函数
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}