致新的一年:不知不觉已经是2023年,祝新的一年大展宏图(兔),前途(兔)似锦,今年梦想实现!

正文:

接触echarts也有很长一段时间了,最近有个很常见的需求,实现省市区下钻,高亮一些有数据的区域例如中国地图的广东省、北京市,接到这个需求,脑海里思考的问题有:(1)通过什么去实现这种下钻文件的拿取 (2)如何实现指定区域的高亮效果(3)地图数据如何跟后端维持一致

产品想实现的效果实际上类似如下+下钻功能:

echarts省市区id(区域编码)实现地图下钻点击(data赋值自定义属性值,geojson信息获取)

问题(1):

对echarts有过经验的会发现echarts上面点击事件默认返回的只有点击区域的name中文值,一般都会通过name值去匹配前端写好的一份如{'广东省':'4400000'}实现对应省份区域编码的拿取,这样是很不科学的,毕竟区域名称并不是一成不变的,后端的中文名字也不一定会跟前端保持一致,所以问题来了,如何让echarts点击事件能返回我们想要的数据,例如返回如data:{name:'广东省',code:4400000,xxx}等数据?直接上实现方案:借助geo图层结合series里面的map层赋值

方案一:name值获取对应文件,准备好省市区对应的区域编码code json文件,获取地图json文件跟实现下钻网上已经有很多好文,在此不再讲实现方案(大神们自行百度google, 棒棒哒)

this.myChart.on('click',params=>{
        // 实现地图下钻
        const {data={}}= params
        const {name=''} = data
        const mapObj = {
          '广东':44000000,
          '上海':xxxxx
        }
        // 获取对应的json文件处理方法
        getMapJSON(`${mapObj[name]}.json`).then(()=>{
          console.log("下钻后对应处理")
        })
      })

方案二:方案一拿到的只能拿到区域名称,并没办法拿到区域编码和相关id,方案二拿取地图geojson文件里面自带对应属性值获取,个人建议这个方法更好,可以自定义一些属性值,直接上例子demo

(1)观察geojson,我们会发现features里面的properties很多情况都会需要使用到,如下

echarts省市区id(区域编码)实现地图下钻点击(data赋值自定义属性值,geojson信息获取)

 (2)思路:获取到这个属性的属性值,实现,上代码:

方法一(需要下钻建议该方式):

 // 方法一:注入文件后拿geoJSON数据中的properties属性
      axios({
        method: "get",
        url: "/china.json",
      }).then((res) => {
        const mapName = "china";
        echarts.registerMap(mapName, (data) => {
          console.log("获取中国地图数据", data);
          let arr = [];
          data.features.forEach((item) => {
            let obj = {
              name: item.properties.name,
              id: (item.properties && item.properties.id) || item.id,
            };
            arr.push(obj);
          });
        });
      });

方法二:

<template>
  <div id="chart" style="height: 800px; width: 800px"></div>
</template>
<script>
import * as echarts from "echarts";
// import axios from "axios";
export default {
  data() {
    return {
      myChart: null,
    };
  },
  mounted() {
    this.setOptions();
  },
  methods: {
    setOptions() {
      this.myChart = echarts.init(document.getElementById("chart"));
      // 方法一:注入文件后拿geoJSON数据中的properties属性
      // axios({
      //   method: "get",
      //   url: "/china.json",
      // }).then((res) => {
      //   const mapName = "china";
      //   echarts.registerMap(mapName, (data) => {
      //     console.log("获取中国地图数据", data);
      //     let arr = [];
      //     data.features.forEach((item) => {
      //       let obj = {
      //         name: item.properties.name,
      //         id: (item.properties && item.properties.id) || item.id,
      //       };
      //       arr.push(obj);
      //     });
      //   });
      // });
      var mapName = "china";
      var data = [
        { name: "北京", value: 199 },
        { name: "天津", value: 42 },
        { name: "河北", value: 102 },
        { name: "山西", value: 81 },
        { name: "内蒙古", value: 47 },
        { name: "辽宁", value: 67 },
        { name: "吉林", value: 82 },
        { name: "黑龙江", value: 123 },
        { name: "上海", value: 24 },
        { name: "江苏", value: 92 },
        { name: "浙江", value: 114 },
        { name: "安徽", value: 109 },
        { name: "福建", value: 116 },
        { name: "江西", value: 91 },
        { name: "山东", value: 119 },
        { name: "河南", value: 137 },
        { name: "湖北", value: 116 },
        { name: "湖南", value: 114 },
        { name: "重庆", value: 91 },
        { name: "四川", value: 125 },
        { name: "贵州", value: 62 },
        { name: "云南", value: 83 },
        { name: "西藏", value: 9 },
        { name: "陕西", value: 80 },
        { name: "甘肃", value: 56 },
        { name: "青海", value: 10 },
        { name: "宁夏", value: 18 },
        { name: "新疆", value: 180 },
        { name: "广东", value: 123 },
        { name: "广西", value: 59 },
        { name: "海南", value: 14 },
      ];
      var geoCoordMap = {};
      var toolTipData = [
        {
          name: "北京",
          value: [
            { name: "科技人才总数", value: 95 },
            { name: "理科", value: 82 },
          ],
        },
        {
          name: "天津",
          value: [
            { name: "文科", value: 22 },
            { name: "理科", value: 20 },
          ],
        },
        {
          name: "河北",
          value: [
            { name: "文科", value: 60 },
            { name: "理科", value: 42 },
          ],
        },
        {
          name: "山西",
          value: [
            { name: "文科", value: 40 },
            { name: "理科", value: 41 },
          ],
        },
        {
          name: "内蒙古",
          value: [
            { name: "文科", value: 23 },
            { name: "理科", value: 24 },
          ],
        },
        {
          name: "辽宁",
          value: [
            { name: "文科", value: 39 },
            { name: "理科", value: 28 },
          ],
        },
        {
          name: "吉林",
          value: [
            { name: "文科", value: 41 },
            { name: "理科", value: 41 },
          ],
        },
        {
          name: "黑龙江",
          value: [
            { name: "文科", value: 35 },
            { name: "理科", value: 31 },
          ],
        },
        {
          name: "上海",
          value: [
            { name: "文科", value: 12 },
            { name: "理科", value: 12 },
          ],
        },
        {
          name: "江苏",
          value: [
            { name: "文科", value: 47 },
            { name: "理科", value: 45 },
          ],
        },
        {
          name: "浙江",
          value: [
            { name: "文科", value: 57 },
            { name: "理科", value: 57 },
          ],
        },
        {
          name: "安徽",
          value: [
            { name: "文科", value: 57 },
            { name: "理科", value: 52 },
          ],
        },
        {
          name: "福建",
          value: [
            { name: "文科", value: 59 },
            { name: "理科", value: 57 },
          ],
        },
        {
          name: "江西",
          value: [
            { name: "文科", value: 49 },
            { name: "理科", value: 42 },
          ],
        },
        {
          name: "山东",
          value: [
            { name: "文科", value: 67 },
            { name: "理科", value: 52 },
          ],
        },
        {
          name: "河南",
          value: [
            { name: "文科", value: 69 },
            { name: "理科", value: 68 },
          ],
        },
        {
          name: "湖北",
          value: [
            { name: "文科", value: 60 },
            { name: "理科", value: 56 },
          ],
        },
        {
          name: "湖南",
          value: [
            { name: "文科", value: 62 },
            { name: "理科", value: 52 },
          ],
        },
        {
          name: "重庆",
          value: [
            { name: "文科", value: 47 },
            { name: "理科", value: 44 },
          ],
        },
        {
          name: "四川",
          value: [
            { name: "文科", value: 65 },
            { name: "理科", value: 60 },
          ],
        },
        {
          name: "贵州",
          value: [
            { name: "文科", value: 32 },
            { name: "理科", value: 30 },
          ],
        },
        {
          name: "云南",
          value: [
            { name: "文科", value: 42 },
            { name: "理科", value: 41 },
          ],
        },
        {
          name: "西藏",
          value: [
            { name: "文科", value: 5 },
            { name: "理科", value: 4 },
          ],
        },
        {
          name: "陕西",
          value: [
            { name: "文科", value: 38 },
            { name: "理科", value: 42 },
          ],
        },
        {
          name: "甘肃",
          value: [
            { name: "文科", value: 28 },
            { name: "理科", value: 28 },
          ],
        },
        {
          name: "青海",
          value: [
            { name: "文科", value: 5 },
            { name: "理科", value: 5 },
          ],
        },
        {
          name: "宁夏",
          value: [
            { name: "文科", value: 10 },
            { name: "理科", value: 8 },
          ],
        },
        {
          name: "新疆",
          value: [
            { name: "文科", value: 36 },
            { name: "理科", value: 31 },
          ],
        },
        {
          name: "广东",
          value: [
            { name: "文科", value: 63 },
            { name: "理科", value: 60 },
          ],
        },
        {
          name: "广西",
          value: [
            { name: "文科", value: 29 },
            { name: "理科", value: 30 },
          ],
        },
        {
          name: "海南",
          value: [
            { name: "文科", value: 8 },
            { name: "理科", value: 6 },
          ],
        },
      ];
      /*获取地图数据*/
      this.myChart.showLoading();
      var mapFeatures = echarts.getMap(mapName).geoJson.features;
      console.log("获取地图geojson文件数据", mapFeatures);
      let arr = [];
      mapFeatures.forEach((item) => {
        let obj = {
          name: item.properties.name,
          id: (item.properties && item.properties.id) || item.id,
        };
        arr.push(obj);
      });
      this.myChart.hideLoading();
      mapFeatures.forEach(function (v) {
        // 地区名称
        var name = v.properties.name;
        // 地区经纬度
        geoCoordMap[name] = v.properties.cp;
      });
      console.log(data);
      console.log(toolTipData);
      var convertData = function (data) {
        var res = [];
        for (var i = 0; i < data.length; i++) {
          var geoCoord = geoCoordMap[data[i].name];
          if (geoCoord) {
            res.push({
              name: data[i].name,
              value: geoCoord.concat(data[i].value),
            });
          }
        }
        return res;
      };
      const option = {
        tooltip: {
          padding: 0,
          enterable: true,
          transitionDuration: 1,
          textStyle: {
            color: "#000",
            decoration: "none",
          },
        },
        // 目前还没有visualMap与geo结合的方案,后续找到方案再更新,有大神也欢迎提供分享方案
        geo: {
          show: true,
          map: mapName,
          roam: true, // 开启缩放,注意把setOption第二个属性值设置为true
          regions: data.map((item) => {
            // 在此自定义其他逻辑的颜色
            item = Object.assign(item, {
              label: {
                normal: {
                  show: true,
                },
                emphasis: {
                  show: false,
                  textStyle: {
                    color: "#fff",
                  },
                },
              },
              itemStyle: {
                normal: {
                  areaColor: "#031525",
                  borderColor: "#3B5077",
                },
                emphasis: {
                  areaColor: "#2B91B7",
                },
              },
            });
            return item;
          }), // 将突出某个省份颜色迁移到geo中去实现
        },
        series: [
          {
            name: "散点",
            type: "scatter",
            coordinateSystem: "geo",
            data: convertData(data),
            symbolSize: function (val) {
              return val[2] / 10;
            },
            label: {
              normal: {
                formatter: "{b}",
                position: "right",
                show: true,
              },
              emphasis: {
                show: true,
              },
            },
            itemStyle: {
              normal: {
                color: "#fff",
              },
            },
          },
          {
            type: "map",
            map: mapName,
            geoIndex: 0, // 指定地图图层对应的geo
            aspectScale: 0.75, //长宽比
            label: {
              normal: {
                show: true,
              },
              emphasis: {
                show: false,
                textStyle: {
                  color: "#fff",
                },
              },
            },
            roam: true,
            itemStyle: {
              normal: {
                areaColor: "#031525",
                borderColor: "#3B5077",
              },
              emphasis: {
                areaColor: "#2B91B7",
              },
            },
            animation: false,
            showLegendSymbol: false, // 存在legend时显示
            // 注意注意:此处data不用于渲染省份高亮数组,而是用于把geojson中的属性值赋值,以便点击时候能拿到对应信息
            data: arr,
          },
          {
            name: "点",
            type: "scatter",
            coordinateSystem: "geo",
            zlevel: 6,
          },
          {
            name: "Top 5",
            type: "effectScatter",
            coordinateSystem: "geo",
            data: convertData(
              data
                .sort(function (a, b) {
                  return b.value - a.value;
                })
                .slice(0, 10)
            ),
            symbolSize: function (val) {
              return val[2] / 10;
            },
            showEffectOn: "render",
            rippleEffect: {
              brushType: "stroke",
            },
            hoverAnimation: true,
            label: {
              normal: {
                formatter: "{b}",
                position: "left",
                show: false,
              },
            },
            itemStyle: {
              normal: {
                color: "yellow",
                shadowBlur: 10,
                shadowColor: "yellow",
              },
            },
            zlevel: 1,
          },
        ],
      };
      // 加上true可以防止开启geo中roam导致的重绘位置偏移
      this.myChart.setOption(option, true);
      // 防止重复触发点击事件
      this.myChart.off("click");
      this.myChart.on("click", (params) => {
        // 实现地图下钻
        const { data = {} } = params;
        console.log("data", data);
      });
    },
  },
};
</script>

执行代码打开控制台即可看到相关数据输出

问题(2):

如何对对应的省份进行颜色渲染或者高亮,上面问题(1)中的方案二可以发现,有两种实现方案

方法一:在series里面map层赋值data,结合visualMap设置颜色根据值分层

    visualMap: {
        show: true,
        min: 0,
        max: 200,
        left: '10%',
        top: 'bottom',
        calculable: true,
        seriesIndex: [1],
        inRange: {
            color: ['#04387b', '#467bc0'] // 蓝绿
        }
    },
    series里面:
    {
            type: 'map',
            map: mapName,
            geoIndex: 0,
            aspectScale: 0.75, //长宽比
            showLegendSymbol: false, // 存在legend时显示
            label: {
                normal: {
                    show: true
                },
                emphasis: {
                    show: false,
                    textStyle: {
                        color: '#fff'
                    }
                }
            },
            roam: true,
            itemStyle: {
                normal: {
                    areaColor: '#031525',
                    borderColor: '#3B5077',
                },
                emphasis: {
                    areaColor: '#2B91B7'
                }
            },
            animation: false,
            data: data
        },

方法二:在geo的regions里面渲染,样式逻辑也只能自己去渲染,目前还没有很好的方案可以让geo的区域颜色结合上visualMap的区块颜色渲染逻辑,data此时存放的是所有省份的属性信息

var mapFeatures = echarts.getMap(mapName).geoJson.features;
      console.log("获取地图geojson文件数据", mapFeatures);
      let arr = [];
      mapFeatures.forEach((item) => {
        let obj = {
          name: item.properties.name,
          id: (item.properties && item.properties.id) || item.id,
        };
        arr.push(obj);
      });

问题(3):

一遇到这种问题估计得前后端干一架才能统一,前端目前也只能手动修改geo里面的id,不过目前感觉geojson里面的编码还是比较标准的,毕竟有个国际标准在那,也只能发现哪些不太匹配的就去改哪个了~

附:

文章引用的大神demo:https://madeapie.com/#/chartInfo/xnmZ5X4gCz

中国地图json文件链接:https://madeapie.com/dep/echarts/map/js/china.js

发表回复