echarts画中国地图及省份切换

2022-09-23 13:19:16 浏览数 (1)

最近用 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 长什么样子。

代码语言:javascript复制
{
    "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 画地图

安装 vueecharts ,先来个简单的正方形。

代码语言:javascript复制
{
    "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 文件、设置 opitonsseries 属性。

代码语言:javascript复制
<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 即可。

值得注意的是,如果我们设置注册的名字为 chinaecharts 会自动给我们加上南沙群岛的放大图:

代码语言:javascript复制
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 ,名字一定要一致。

代码语言:javascript复制
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 选项。

代码语言:javascript复制
const option = {
  ...
  tooltip: {
    trigger: "item",
  },
  ...
}

视觉映射

我们可以通过 visualMap 选项,将数据分组。

代码语言:javascript复制
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 组件来调度两个组件的显示隐藏。

代码语言:javascript复制
<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 组件。

代码语言:javascript复制
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 组件。

代码语言:javascript复制
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

通过 GeoJSONecharts ,知道大致的原理,然后其他配置项参考 官网 和 社区 的例子比对上 配置项 慢慢配置即可,文章的整体代码放到了 github,需要的同学可以参考。

ECharts 最初由百度团队开源,并于 2018 年初捐赠给Apache 基金会,2021126 日晚,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

0 人点赞