这是我参与「第四届青训营 」笔记创作活动的第7天,本期青训营需要用到大量的图对数据进行可视化分析,因此选择了echarts这个开源的javascript的开源可视化图标库。
echarts组件的封装
实际在项目中使用时很多页面需要使用到图表,因此需要对此做一个封装实现一个echarts通用组件,对这个组件只需要传入配置项option就可以实现,option的详细配置方式见官方文档[Documentation - Apache ECharts]。
获取DOM节点
根据官方文档,echarts是需要挂载到Dom节点上的,官网介绍的都是使用getElementById的方式获取,这就要求给div设置id,但是在react这类框架时可以使用ref来获取节点,因此就回避了设置id以获取DOM的方式
export const Map = ({ option }: { option: any }) => {
const ref = useRef<HTMLDivElement>(null);
return (
<div
className={style.areaMap}
ref={ref!}
></div>
);
};
echarts图表自适应
根据官方文档,echarts挂载的dom节点必须设置具体的宽度和高度才可以显示出来(不可以直接设置宽高为100%来继父盒子),但由于web上不同的显示器分辨率不同,需要做到自适应,因此echarts的图大小不能定死,可以先引入echatrs处理自适应提供的API来适应自己的DOM
useEffect(() => {
window.onresize = function () {
mapInstance.resize();
};
return () => {
mapInstance && mapInstance.dispose();
};
}, []);
为了自适应全体的布局,故而给父盒子一般以flex布局的方式设置flex的份额来确定父盒子响应式的宽高,这时再给echarts继承父盒子的宽高100%就可以实现echarts自适应大小了。
完整实现
import * as echarts from "echarts";
import { useEffect, useRef } from "react";
import style from "./map.module.scss";
export const Map = ({ option }: { option: any }) => {
const ref = useRef<HTMLDivElement>(null);
let mapInstance: any = null;
const renderMap = () => {
const renderedMapInstance = echarts.getInstanceByDom(ref.current!);
if (renderedMapInstance) {
mapInstance = renderedMapInstance;
} else {
mapInstance = echarts.init(ref.current!);
}
mapInstance?.setOption(option);
};
useEffect(() => {
renderMap();
}, []);
useEffect(() => {
window.onresize = function () {
mapInstance.resize();
};
return () => {
mapInstance && mapInstance.dispose();
};
}, []);
return (
<div
style={{ width: "100%", height: "100%" }}
ref={ref!}
></div>
);
};
echarts实现中国地图
本部分的实现参考了本文vue+Echarts中国地图绘教程最新版2021(无废话版,价值几十亿,收藏备用) - 掘金 (juejin.cn)。
echarts在5.0之后就移除了中国地图的json文件,但是4.9有内置中国地图的json,于是先下载4.9根据路径获取地图文件数据
npm install echarts@4.9.0
根据路径在node_moudles下找到echarts/map/json/china.json,复制文件
import china from 'echarts/map/json/china.json'
然后卸载4.9在安装最新版本的echarts即可,剩下的实现对世界地图组件的封装和前文基本类似就不再赘述
import * as echarts from "echarts";
import { useEffect, useRef } from "react";
import china from "./china.json";
import { mapOptions } from "./config";
export const WorldMap = () => {
const ref = useRef<HTMLDivElement>(null);
let mapInstance: any = null;
const renderMap = () => {
const renderedMapInstance = echarts.getInstanceByDom(ref.current!);
if (renderedMapInstance) {
mapInstance = renderedMapInstance;
} else {
mapInstance = echarts.init(ref.current!);
}
mapInstance.setOption(mapOptions);
};
useEffect(() => {
echarts.registerMap("china", china as any);
renderMap();
}, []);
useEffect(() => {
window.onresize = function () {
mapInstance.resize();
};
return () => {
mapInstance && mapInstance.dispose();
};
}, []);
return <div style={{ width: "55vw", height: "65vh" }} ref={ref!}></div>;
};