angular中对echarts图表进行封装(环形进度条、双Y轴
2022-02-09 本文已影响0人
听书先生
在大屏的开发过程中,需要大量的使用echarts图表,我们可以腾出时间将echarts图表进行二次封装,以便后期循环使用。
1、二次封装echarts:
封装为公共组件,在使用的时候只需要传入option项即可
import { AfterViewInit, Component, ElementRef, Input, OnDestroy } from "@angular/core";
import * as echarts from 'echarts';
@Component({
selector: 'my-charts',
template: ``,
styles: [`
:host {
display: inline-block;
height: 100%;
width: 100%;
padding: 0;
margin: 0;
border: none;
cursor: pointer;
overflow: hidden;
}
`]
})
export class MYChartsComponent implements AfterViewInit, OnDestroy {
chart;
_option;
constructor(private el: ElementRef) {
}
@Input()
set option(option) {
this._option = option
if (this.chart) {
this.chart.setOption(option, true);
}
}
ngAfterViewInit() {
this.chart = echarts.init(this.el.nativeElement);
this.chart.setOption(this._option, true);
window.addEventListener('resize', this.onWindowResize)
}
onWindowResize = () => {
this.chart.resize()
}
ngOnDestroy() {
window.removeEventListener('resize', this.onWindowResize)
}
}
2、将不同的echarts图表封装到一个charts.options.ts文件中:
这个文件将你所有图表的配置项写成key-value的形式存入进去,这样可以在你使用到某个相同的echarts图表时,只需要在外部动态的修改data数据即可。
import * as echarts from "echarts";
const CHARTS_OPTION = {
progressAllotment: {
// 环形进度条的代码部分
},
taskNumByMonth: {
// 双Y轴折线区域图
}
};
export { CHARTS_OPTION };
环形进度条说明:
环形进度条有一些地方需要记录一下:
- 1、echarts环形使用
top: 'center'
默认是依据的主标题居中对齐,因此,再去加入副标题时,就会产生没有垂直居中对齐的情况,需要手动修改top: '40%'
的百分比 - 2、
clockwise
属性设置为true指的是环形为顺时针展示
参考图例.png - 参考代码:
progressAllotment: {
title: {
text: 0 + "%",
textStyle: {
color: "#9A9EBA",
fontSize: 18,
},
subtext: "当日配款进度",
subtextStyle: {
fontSize: 16,
color: "#106199",
},
align: "auto",
itemGap: 10,
left: "center",
top: "40%",
},
angleAxis: {
max: 100,
clockwise: true,
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
},
radiusAxis: {
type: "category",
axisLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
splitLine: {
show: false,
},
},
polar: {
center: ["50%", "50%"],
radius: "160%", //图形大小
},
series: [
{
type: "bar",
data: [
{
name: "当前配款进度",
value: 0,
itemStyle: {
normal: {
color: "#15A3EF",
},
},
},
],
coordinateSystem: "polar",
roundCap: true,
barWidth: 10,
barGap: "-100%", // 两环重叠
z: 2,
},
{
type: "bar",
data: [
{
value: 100,
itemStyle: {
color: "#1E3566",
shadowColor: "rgba(0, 0, 0, 0.2)",
shadowOffsetY: 2,
},
},
],
coordinateSystem: "polar",
roundCap: true,
barWidth: 10,
barGap: "-100%", // 两环重叠
z: 1,
},
],
},
双Y轴折线区域图:
这里同样有些地方需要留意的,在echarts3.0版本以上,貌似y轴坐标就需要手动去划分刻度以及设置最大值或最小值。
- 1、双y轴显示:在yAxis配置了两个对象内容的基础上,将series中的第二个对象的yAxisIndex设为1即可
- 2、左右坐标轴刻度不均等,导致间隔出现大小不一:使用
interval: Math.ceil(坐标的最大值 / 4)
这样就成功的划分为了4等分 - 3、折线图渐变区域块的设置:渐变区域的话只需要在areaStyle中去设置渐变颜色即可
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#74EAB0", // 0% 处的颜色
},
{
offset: 0.1,
color: "#448AC8", // 10% 处的颜色
},
{
offset: 1,
color: "transparent", // 100% 处的颜色
},
]),
},
- 4、拐点的样式自定义:在
series
中去自定义itemStyle
样式即可
itemStyle: {
normal: {
color: "#3AB578",
lineStyle: {
color: "#3AB578",
width: 1,
},
},
},
参考图片.png
- 参考代码:
taskNumByMonth: {
legend: {
data: ["订单数量", "订单金额", "配款耗时"],
icon: "circle",
right: 0,
textStyle: {
color: "white",
},
},
grid: {
left: "5%",
right: "8%",
bottom: "8%",
containLabel: true,
},
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category",
data: ["16号","19号","21号","24号","27号","30号","3号","6号","9号","12号","15号"],
boundaryGap: false,
axisLabel: {
color: "white",
fontSize: 12,
},
axisLine: {
lineStyle: {
color: "#366383",
},
},
axisTick: {
show: false,
},
},
yAxis: [
{
name: "单位: 万元",
nameTextStyle: {
color: "white",
},
type: "value",
axisLabel: {
color: "white",
fontSize: 12,
},
min: 0,
max: 20000, // 最大值
interval: Math.ceil(20000 / 4), // 平均分为4份
splitLine: {
show: true,
lineStyle: {
type: "dashed",
color: "#395275",
},
},
},
{
name: "单位: 分钟",
nameTextStyle: {
color: "white",
},
type: "value",
axisLabel: {
color: "white",
fontSize: 12,
},
min: 0,
max: 160, // 最大值
interval: Math.ceil(160 / 4), // 平均分为4份
splitLine: {
show: true,
lineStyle: {
type: "dashed",
color: "#395275",
},
},
},
],
series: [
{
name: "单位: 万元",
data: [8000,9000,10000,13000,14000,14000,15000,16000,14800,14000,20000],
type: "line",
smooth: false,
symbol: "circle",
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#74EAB0", // 0% 处的颜色
},
{
offset: 0.1,
color: "#448AC8", // 10% 处的颜色
},
{
offset: 1,
color: "transparent", // 100% 处的颜色
},
]),
},
itemStyle: {
normal: {
color: "#3AB578",
lineStyle: {
color: "#3AB578",
width: 1,
},
},
},
yAxisIndex: 0,
},
{
name: "单位: 分钟",
data: [116, 80, 128, 110, 120, 130, 150, 160, 145, 150, 158],
type: "line",
smooth: false,
symbol: "circle",
itemStyle: {
normal: {
color: "#FCB07E",
lineStyle: {
color: "#FCB07E",
width: 1,
type: "dotted",
},
},
},
yAxisIndex: 1,
},
],
}
3、导入配置项,调用公共组件,开始使用echarts:
- 模板代码文件:
<div nz-col nzSpan="12" style="width: 50%;height: 100%;">
<div class="common">
<span class="sub-title left-title">近30天订单量变化趋势图</span>
<zj-charts [option]="chartsOption.taskNumByMonth"></zj-charts>
</div>
</div>
- 组件ts代码部分:
import { HttpClient } from "@angular/common/http";
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
import * as _ from "lodash";
import { of, Subscription, zip } from "rxjs";
import { OrderDataService } from "./order-data.service";
import { CHARTS_OPTION } from "./charts.options";
interface Org {
orgName?: string;
orgAmount?: number;
orgType?: Object;
}
@Component({
selector: "order-data",
templateUrl: "./order-data.component.html",
styleUrls: ["./order-data.component.less"],
})
export class OrderDataComponent implements OnInit, OnDestroy {
subscriptionList = new Array<Subscription>(1);
timeHandleList = new Array(1);
objectKeys = Object.keys;
items: Org = {
orgName: "桃花坞支行",
orgAmount: 120,
orgType: {
"100元": 200,
"50元": 9,
"20元": 19,
"10元": 10,
"5元": 3,
"1元": 2,
"5角": 1,
"1角": 0,
},
};
// 模拟数据
mock = {
task: {},
quota: {},
};
chartsOption = CHARTS_OPTION;
constructor(private http: HttpClient, private _ser: OrderDataService) {}
ngOnInit() {
this.refreshDataOnce();
}
// 刷新订单数据模块的图表数据
refreshDataOnce = () => {
// 模拟数据
let sourceOne = of({
process: {
percent: parseFloat((Math.random() * 100).toFixed(1)),
},
});
this.mock["task"] = {
total: parseFloat((Math.random() * 1000).toFixed(0)),
amount: parseFloat((Math.random() * 10000).toFixed(1)),
};
this.mock["quota"] = {
count: parseFloat((Math.random() * 1000).toFixed(0)),
amount: parseFloat((Math.random() * 10000).toFixed(1)),
};
this.subscriptionList[0] = zip(
sourceOne
).subscribe(([progressAllotment]) => {
this.chartsOption.progressAllotment.series[0].data[0].value = progressAllotment["process"].percent;
this.chartsOption.progressAllotment.title["text"] = progressAllotment["process"].percent + "%";
this.chartsOption = _.cloneDeep(this.chartsOption);
this.timeHandleList[0] = setTimeout(this.refreshDataOnce, 3 * 1000);
},
() => {
this.timeHandleList[0] = setTimeout(this.refreshDataOnce, 3 * 1000);
}
);
};
ngOnDestroy(): void {
this.subscriptionList.forEach((subscription) => subscription.unsubscribe());
this.timeHandleList.forEach((timeHandle) => clearTimeout(timeHandle));
}
}