最近用 ehcarts
写了一个有关中国地图的需求,这篇文章来总结下基本的原理和用法。
Geojson
首先了解一下 GeoJSON
,看下 维基百科 的定义:
★**GeoJSON **是一种基于 JSON 的地理空间数据交换格式,它定义了几种类型 JSON 对象以及它们组合在一起的方法,以表示有关地理要素、属性和它们的空间范围的数据。 2015年,互联网工程任务组(IETF)与原始规范作者组建了一个 GeoJSON 工作组,一起规范 GeoJSON 标准。在2016年8月,推出了最新的GeoJSON数据格式标准规范(RFC 7946)。 GeoJSON 使用唯一地理坐标参考系统 WGS1984 和十进制度单位,一个 GeoJSON 对象可以是 Geometry, Feature 或者FeatureCollection. 其几何对象包括有点(表示地理位置)、线(表示街道、公路、边界)、多边形(表示国家、省、领土),以及由以上类型组合成的复合几何图形。 ”
简单说就是通过坐标系来描述点、线、面,看几个例子就明白它们是什么了。
单个点:"type": "Point"
image-20220510095405517
多个点,"type": "MultiPoint"
image-20220510095158715
多个线:"type": "MultiLineString"
image-20220510095241321
多个面:"type": "MultiPolygon"
image-20220510095257874
地图 Geojson
中国地图和省份的 geoJson
可以在 echarts-map 或者阿里的 数据可视化中心 进行下载。
image-20220510101045037
echarts 4.x
的版本自带了一些 Geojson
的数据,在 node_modules/echarts/map/json
目录,但可能考虑到一些省区数据不能及时更新,echarts 5
版本就没有自带数据了。
让我们看一下全国地图中山西省的 geoJson
长什么样子。
{
"type": "FeatureCollection",
"features": [
...
{
...
}
{
"type": "Feature",
"properties": {
"adcode": 140000,
"name": "山西省",
"center": [112.549248, 37.857014],
"centroid": [112.304436, 37.618179],
"childrenNum": 11,
"level": "province",
"parent": { "adcode": 100000 },
"subFeatureIndex": 3,
"acroutes": [100000]
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[110.379257, 34.600612],
[110.424837, 34.588295],
[110.488279, 34.610956],
[110.533242, 34.583368],
[110.610851, 34.607508],
[110.710017, 34.605045],
[110.749437, 34.65232],
[110.791937, 34.649858],
[110.824582, 34.615881],
[110.883712, 34.64395],
[110.903422, 34.669056],
[110.920052, 34.730068],
...
]
]
]
}
},
{
...
}
...
]
}
整体是一个 "type": "FeatureCollection"
,然后有一个 features
数组保存所有省份,每一个都是 "type": "Feature"
,代表单个省份。包含 properties
属性和 geometry
属性。geometry
属性就是所有的坐标信息。
根据坐标信息,计算最大值和最小值的差值,按比例映射到 canvas
上的坐标,然后就可以画出来了,细节的话可以参考 b 站 的这个视频。
echarts 画地图
安装 vue
和 echarts
,先来个简单的正方形。
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "正方形"
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
]
}
}
]
}
然后用 echarts
做引入我们的 json
文件、通过 echarts.registerMap
注册 json
文件、设置 opitons
的series
属性。
<template>
<div id="main" style="width: 600px; height: 600px"></div>
</template>
<script>
import * as echarts from "echarts";
import test from '../data/test'
export default {
name: "HelloWorld",
props: {
},
mounted() {
var myChart = echarts.init(document.getElementById("main"));
echarts.registerMap('mapName', test); // 注册地图
let option = {
series: [
{
type: "map",
map: 'mapName', // 引入地图数据
},
],
};
myChart.setOption(option);
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
image-20220511080857038
然后我们只需要到阿里的 数据可视化中心 把中国地图的 Geojson
数据下载下来,替换上边的 test.json
即可。
值得注意的是,如果我们设置注册的名字为 china
,echarts
会自动给我们加上南沙群岛的放大图:
import * as echarts from "echarts";
import china from '../data/china'
export default {
name: "HelloWorld",
props: {
},
mounted() {
var myChart = echarts.init(document.getElementById("main"));
echarts.registerMap('china', china);
let option = {
series: [
{
type: "map",
map: 'china', // 引入地图数据
},
],
};
myChart.setOption(option);
},
};
可能会用到的 options 属性
地图画出来以后,接下来可以照着 echarts 官网 变身为「echarts
配置工程师」了,记得注意一下自己当前的 eharts
版本。
设置悬浮上的数据
我们在 series
中引入 data
,加一点随机数据,其中 name
值是 json
数据中的 properties
对应的 name
,名字一定要一致。
const option = {
...
series: [
{
type: "map",
map: "china", // 引入地图数据
name: "省份随机数据",
data: [
{
name: "北京市",
value: 21,
},
{
name: "天津市",
value: 12,
},
{
name: "上海市",
value: 99,
},
{
name: "重庆市",
value: 98,
},
{
name: "河北省",
value: 99,
},
{
name: "河南省",
value: 29,
},
{
name: "云南省",
value: 79,
},
{
name: "辽宁省",
value: 38,
},
{
name: "黑龙江省",
value: 4,
},
{
name: "湖南省",
value: 32,
},
{
name: "安徽省",
value: 84,
},
{
name: "山东省",
value: 72,
},
{
name: "新疆维吾尔自治区",
value: 99,
},
{
name: "江苏省",
value: 70,
},
{
name: "浙江省",
value: 85,
},
{
name: "江西省",
value: 11,
},
{
name: "湖北省",
value: 62,
},
{
name: "广西壮族自治区",
value: 13,
},
{
name: "甘肃省",
value: 74,
},
{
name: "山西省",
value: 78,
},
{
name: "内蒙古自治区",
value: 74,
},
{
name: "陕西省",
value: 40,
},
{
name: "吉林省",
value: 9,
},
{
name: "福建省",
value: 90,
},
{
name: "贵州省",
value: 57,
},
{
name: "广东省",
value: 6,
},
{
name: "青海省",
value: 52,
},
{
name: "西藏自治区",
value: 10,
},
{
name: "四川省",
value: 98,
},
{
name: "宁夏回族自治区",
value: 11,
},
{
name: "海南省",
value: 25,
},
{
name: "台湾省",
value: 86,
},
{
name: "香港特别行政区",
value: 8,
},
{
name: "澳门特别行政区",
value: 50,
},
],
},
],
...
}
再补上 tooltip
选项。
const option = {
...
tooltip: {
trigger: "item",
},
...
}
视觉映射
我们可以通过 visualMap
选项,将数据分组。
const option = {
...
visualMap: {
left: "right",
min: 0,
max: 100,
inRange: {
color: [
"#313695",
"#4575b4",
"#74add1",
"#abd9e9",
"#e0f3f8",
"#ffffbf",
"#fee090",
"#fdae61",
"#f46d43",
"#d73027",
"#a50026",
],
},
text: ["High", "Low"],
calculable: true,
},
...
}
设置后之后,我们可以滑动右下角的范围来选取不同的省份。
除了滑块的映射,还支持分区间的,类似下边这种。
image-20220512084908512
其他选项
其他选项这里就不介绍了,可以参考 官网 和 社区 的样例,然后结合自己的需求进行配置即可。
贴几张社区上炫酷的地图:
image-20220512085159589
省份切换
下边再实现一下点击省份切换到对应的省份地图的功能。
知道了上边的东西,思路其实很简单了,我们只需要把所有省份的 Geojson
数据全部下载下来,然后监听 echarts
的点击事件去显示省份即可。
为了逻辑之间的解耦,我们可以再新建一个组件,专门展示省份的数据。
代码语言:javascript复制<template>
<div>
<div id="province" style="width: 600px; height: 600px"></div>
</div>
</template>
<script>
import * as echarts from "echarts";
export default {
name: "Province",
props: {
fileName: String,
},
data() {
return {
option: {
series: [
{
name: "省份数据",
type: "map",
map: "province",
data: [],
},
],
},
};
},
mounted() {
this.initData();
},
methods: {
initData() {
try {
const provinceJSON = require("../data/province/"
this.fileName);
const myChart = echarts.init(
document.getElementById("province")
);
echarts.registerMap("province", provinceJSON);
myChart.setOption(this.option);
} catch (e) {
alert(`暂无${this.fileName}数据`);
this.$emit("toMap");
}
},
},
};
</script>
<style scoped rel="stylesheet/scss" lang="scss"></style>
我们把省份数据都放到 "../data/province"
目录中,这里简单演示,只下载了两个省份的地图:
image-20220512091724599
通过外部传进来文件的 fileName
注册地图。这里直接通过 require("../data/province" this.fileName)
来动态引入 Geojson
,一定要加上 "../data/province"
前缀来限制文件的位置,关于 webpack
的动态引入的更多细节可以参考 Webpack 打包 commonjs 和 esmodule 动态引入模块的产物对比。
我们增加一个 ProvinceMap
组件来调度两个组件的显示隐藏。
<template>
<div>
<Province
v-if="showProvince"
:fileName="fileName"
@toMap="toMap"
></Province>
<Map v-else @toProvince="toProvince"></Map>
</div>
</template>
<script>
import Province from "./Province.vue";
import Map from "./Map.vue";
export default {
name: "HelloWorld",
components: {
Province,
Map,
},
data() {
return {
showProvince: false,
fileName: null,
};
},
methods: {
// 显示省份数据
toProvince({ fileName } = {}) {
this.fileName = fileName;
this.showProvince = true;
},
// 显示全国地图
toMap() {
this.showProvince = false;
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
在 Map
组件中监听省份的 click
,传递给 ProvinceMap
组件。
initData() {
var myChart = echarts.init(document.getElementById("main"));
echarts.registerMap("china", china);
const option = ....;
myChart.setOption(option);
myChart.on("click", (params) =>
this.$emit("toProvince", { fileName: params.name })
);
},
在 Province
组件中监听 click
,传递给 ProvinceMap
组件。
initData() {
try {
const provinceJSON = require("../data/province/"
this.fileName);
const myChart = echarts.init(
document.getElementById("province")
);
echarts.registerMap("province", provinceJSON);
myChart.setOption(this.option);
myChart.on("click", () => this.$emit("toMap"));
} catch (e) {
alert(`暂无${this.fileName}数据`);
this.$emit("toMap");
}
},
最后看一下实现的效果:
Kapture 2022-05-12 at 10.06.29
总
通过 GeoJSON
画 echarts
,知道大致的原理,然后其他配置项参考 官网 和 社区 的例子比对上 配置项 慢慢配置即可,文章的整体代码放到了 github,需要的同学可以参考。
ECharts
最初由百度团队开源,并于 2018
年初捐赠给Apache
基金会,2021
年 1
月 26
日晚,Apache
基金会官方宣布 ECharts
项目正式毕业,成为 Apache
顶级项目。
平时开发 Echarts
,我们就可以从「切图仔」变成「echarts
配置工程师了」,手动狗头。
文章涉及到的一些外链:
echarts-map: https://github.com/echarts-maps
阿里云 Geojson: https://datav.aliyun.com/portal/school/atlas/area_selector
eharts 官方示例:https://echarts.apache.org/examples/zh/index.html#chart-type-map
echarts 社区示例:https://www.makeapie.cn/echarts_1.html