![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/441dd09e6c654ee7b52a4dfc525344d0.png)
- 父元素传入一次最多显示几个以及每次切换几个
- 超出没两秒向右切换一个
- 图表加载有动画效果
- 动态更新数据实时显示
- 屏幕尺寸改变自动适应
- 字体大小自适应
组件 BarChart.vue
<template>
<div class="w100 h100">
<div
ref="chart"
class="w100 h100"
@mouseenter="stopTimer"
@mouseleave="startTimer"
></div>
</div>
</template>
<script>
import resize from "./mixins/resize";
let color = ["#FFF200", "#ff6200"];
let color1 = ["rgba(255, 225, 128,.6)", "rgba(245, 116, 116,.6)"];
export default {
name: "BarChart",
mixins: [resize],
props: {
chartData: {
type: Array,
required: true,
},
maxVisibleBars: {
type: Number,
default: 6,
},
barsPerStep: {
type: Number,
default: 1,
},
},
data() {
return {
chart: null,
currentIndex: 0,
timer: null,
};
},
mounted() {
this.initChart();
this.startTimer();
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer);
}
if (this.chart) {
this.chart.dispose();
}
},
watch: {
chartData: {
handler: "updateChart",
deep: true,
},
},
methods: {
initChart() {
this.chart = this.$echarts.init(this.$refs.chart);
this.updateChart();
},
updateChart() {
const visibleData = this.chartData.slice(
this.currentIndex,
this.currentIndex + this.maxVisibleBars
);
const option = {
color: ["#FFF200", "#ff6200"],
animation: true,
animationDuration: 1000,
animationEasing: "cubicInOut",
animationDurationUpdate: 500,
animationEasingUpdate: "cubicInOut",
title: {
text: "动态柱图",
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.2),
},
left: "center",
top: "2%",
},
tooltip: {
show: true,
trigger: "item",
formatter: "{b}{a}: {c}",
backgroundColor: "#f9f9f9",
borderColor: "#ccc",
borderWidth: 1,
padding: [5, 10],
textStyle: {
color: "#333",
fontSize: 14,
},
},
grid: {
top: "20%",
left: "6%",
right: "1%",
bottom: "4%",
containLabel: true,
},
legend: {
itemHeight: this.fontSize(0.12),
itemWidth: this.fontSize(0.2),
itemGap: this.fontSize(0.23),
textStyle: {
color: "#fff",
borderColor: "#fff",
fontSize: this.fontSize(0.14),
},
top: 7,
right: 20,
},
xAxis: {
type: "category",
data: visibleData.map((item) => item.name),
boundaryGap: true,
axisLine: {
lineStyle: {
color: "#2384B1",
width: this.fontSize(0.01),
},
},
axisLabel: {
interval: 0,
rotate: 30,
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
axisTick: {
show: false,
},
},
yAxis: {
type: "value",
min: 0,
minInterval: 1,
splitLine: {
show: true,
lineStyle: {
color: "#023052",
type: "dotted",
},
},
axisLine: {
lineStyle: {
color: "#2384B1",
width: this.fontSize(0.01),
},
},
axisLabel: {
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
},
series: [
{
name: "数量",
data: visibleData.map((item) => item.value),
type: "bar",
barWidth: this.fontSize(0.2),
barMinHeight: 2,
itemStyle: {
normal: {
show: true,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: color[0],
},
{
offset: 1,
color: color1[0],
},
]),
barBorderRadius: [4, 4, 0, 0],
shadowColor: color1[0],
shadowBlur: 24,
},
},
label: {
normal: {
show: true,
position: "top",
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
},
},
],
};
this.chart.setOption(option);
},
startTimer() {
this.timer = setInterval(() => {
this.currentIndex += this.barsPerStep;
if (this.currentIndex + this.maxVisibleBars > this.chartData.length) {
this.currentIndex = 0;
}
this.updateChart();
}, 2000);
},
stopTimer() {
clearInterval(this.timer);
},
},
};
</script>
<style scoped>
</style>
父组件
<template>
<div id="app" style="background: #000">
<BarChart style="width: 500px; height: 400px" :chartData="data" />
<button @click="updateData">更新数据</button>
</div>
</template>
<script>
import BarChart from "./components/BarChart.vue";
export default {
components: {
BarChart,
},
data() {
return {
data: [
{ name: "项目1", value: 20 },
{ name: "项目2", value: 30 },
{ name: "项目3", value: 10 },
{ name: "项目4", value: 40 },
{ name: "项目5", value: 0 },
{ name: "项目6", value: 0.5 },
{ name: "项目7", value: 1 },
{ name: "项目8", value: 45 },
{ name: "项目9", value: 30 },
{ name: "项目10", value: 20 },
],
};
},
methods: {
updateData() {
this.$set(this.data, 4, {
name: "更新后的项目",
value: Math.random() * 100,
});
},
},
};
</script>
/mixins/resize.js
import { debounce } from "@/utils";
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null,
};
},
mounted() {
this.initListener();
},
activated() {
if (!this.$_resizeHandler) {
this.initListener();
}
this.resize();
},
beforeDestroy() {
this.destroyListener();
},
deactivated() {
this.destroyListener();
},
methods: {
fontSize(res) {
let docEl = document.documentElement,
clientWidth =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
if (!clientWidth) return;
let fontSize = 100 * (clientWidth / 1920);
return res * fontSize;
},
$_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();
},
},
};
对比原来柱状图
<template>
<div class="w100 h100">
<div class="flex-3 h100" ref="chart6" />
</div>
</template>
<script>
import resize from "./mixins/resize";
let color = ["#FFF200", "#ff6200"];
let color1 = ["rgba(255, 225, 128,.6)", "rgba(245, 116, 116,.6)"];
export default {
mixins: [resize],
props: ["list"],
watch: {
list: {
handler(val) {
this.initChart();
let month = val.monthOrDayOrTimeList;
let orderNum = val.administrativeDivisionList;
let option = {
xAxis: [
{
data: month,
},
],
series: [
{
name: "火灾总量",
data: orderNum,
},
],
};
this.chart.setOption(option);
if (this.timeId) {
clearInterval(this.timeId);
this.timeId = null;
}
if (month.length > this.maxNum) {
let num = 0;
this.timeId = setInterval(() => {
if (num + this.maxNum == month.length) {
num = 0;
} else {
num += 1;
}
let option = {
dataZoom: [
{
startValue: num,
endValue: num + this.maxNum - 1,
},
],
};
this.chart.setOption(option);
}, 3000);
}
},
deep: true,
},
},
data() {
return {
chart: null,
maxNum: 12,
timeId: null,
};
},
mounted() {
console.log("tab1Bar来了");
this.$nextTick(() => {
this.initChart();
});
},
beforeDestroy() {
console.log("tab1Bar走了");
if (!this.chart) {
return;
}
this.chart = null;
clearInterval(this.timeId);
this.timeId = null;
},
methods: {
init() {},
initChart() {
this.chart = this.$echarts.init(this.$refs.chart6);
let option = {
grid: {
top: "20%",
left: "6%",
right: "1%",
bottom: "4%",
containLabel: true,
},
tooltip: {
show: true,
trigger: "item",
formatter: "{b}: {c}",
},
dataZoom: [
{
xAxisIndex: 0,
show: false,
type: "inside",
startValue: 0,
endValue: this.maxNum - 1,
},
],
xAxis: [
{
type: "category",
boundaryGap: true,
axisLine: {
lineStyle: {
color: "#2384B1",
width: this.fontSize(0.01),
},
},
axisLabel: {
interval: 0,
rotate: 30,
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
axisTick: {
show: false,
},
},
],
yAxis: [
{
type: "value",
min: 0,
minInterval: 1,
splitLine: {
show: true,
lineStyle: {
color: "#023052",
type: "dotted",
},
},
axisLine: {
show: false,
},
axisLabel: {
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
},
],
legend: {
itemHeight: this.fontSize(0.12),
itemWidth: this.fontSize(0.2),
itemGap: this.fontSize(0.23),
textStyle: {
color: "#fff",
borderColor: "#fff",
fontSize: this.fontSize(0.14),
},
top: 7,
right: 20,
},
series: [
{
name: "",
type: "bar",
barWidth: this.fontSize(0.2),
itemStyle: {
normal: {
show: true,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: color[0],
},
{
offset: 1,
color: color1[0],
},
]),
barBorderRadius: [4, 4, 0, 0],
shadowColor: color1[0],
shadowBlur: 24,
},
},
label: {
normal: {
show: true,
position: "top",
textStyle: {
color: "#fff",
fontSize: this.fontSize(0.13),
},
},
},
},
],
};
this.chart.setOption(option);
},
},
};
</script>
<style lang="sass" scoped>
@import "./css/rem.scss"
</style>