Echarts 5实现世界地图

4,358 阅读6分钟

这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

如果问我参加工作以来,用得最多的库是什么?那一定是Echarts,这不,前段时间刚刚结束了一段疯狂的开发-仪表板,实现最多的就是图表。其实在这之前,我也实现过图表,接下来,我会把实现过程中,踩过的坑,和比较难找的配置项来具体说一下。

本期主要说一下Echarts实现世界地图,其他图表例如半圆环,气泡图,词云图等等,将放在明天来讲。

Echarts实现世界地图

之前写过用Highcharts来实现世界地图,当时踩了很多坑,走了很多弯路。咦,这次又来个需求,实现世界地图,我想这次实现起来可方便了,尽管Highcharts很牛,奈何有他的缺点,大家应该懂。行吧,转到用Echarts,这一路,可没少踩坑。

其中有几个点我一一罗列一下:

  • 将世界地图初步展现出来;
  • 将世界地图某些国家按照右侧图例,对应颜色展示出来
  • 右侧放大缩小按钮来控制地图缩放
  • 世界地图上点击任何一个国家,会显示黄色,调整该颜色
  • 点击图例后,图例颜色会变浅,做调整
  • 点击图例后,再点击某个国家,该国家颜色会有变化,需调整 其实上面提到的几个点,正是我在实现过程中需要解决的问题。接下来一一讲解,会包含我的解决思路及具体实现方案。

将世界地图初步展现出来

我用Echarts做图表有一个规律,一般会先去官方提供的demo引进来,运行成功后调整部分内容,改为自己需要的形式。本次也是一样,因为第一次使用Echarts实现地图功能,所以先拿个demo跑一跑,试一试。

问题1:api.coord is not a function 这一问题困扰了我好久,最终我没有使用该APi。不过还是有一个排查的过程,现在大致来说一下。

api.coord来自于配置项renderItem,好,那就去官网查找该配置项。就是这儿echarts.apache.org/zh/option.h…

现在想来,应该是我没有引入坐标的问题吧(时间原因,我没有具体试,后期找个时间查一下)。

问题2:Echarts实现中国地图只显示title,不显示地图。 基于上述demo无果,我发现官网提供的这个demo是没有api.coord的,我当时想使用这个demo是不是就可以略过上述问题了,因此换为了官网的另一个demo。

使用该demo还算顺利,不报错了,但是只显示了一个title。就是下面这种效果。

image.png

原因是没有引入地理坐标系组件。就是下述配置项:echarts.apache.org/zh/option.h…

加上之后,中国地图出现了,但是还不是demo中的样子。因为我不需要打点,所以没有继续处理。

geo: {
      //     表示世界地图,中国地图直接改为china
      map: 'china',
        type: 'effectScatter',
        coordinateSystem: 'bmap',
        mapType: 'world',
        data: convertData(
          data
            .sort(function (a, b) {
              return b.value - a.value;
            })
            .slice(0, 6)
        ),
        data: convertData(data
          .sort(function (a, b) {
            return b.value - a.value;
          })
          .slice(0, 6)),
        symbolSize: function (val) {
          return val[2] / 10;
        },
      }
    ]
  }

问题3: 要引入百度地图的AK? 在排查问题的过程中,有的说要申请ak,咱这儿是不需要的。咱们没有直接引百度地图。

将世界地图某些国家按照右侧图例,对应颜色展示出来

先提一下,右侧的图例是如何处理的? 这里用到的配置项是VisalMap,称为:视觉映射组件,具体api地址是:echarts.apache.org/zh/option.h… 该参数又分为连续和分段型。 (1)连续,type值为continuous。样式是这样的: image.png (2)不连续,type值为piecewise,样式是这样的: image.png 最初我加了连续,在我的世界地图上中国,俄罗斯等四个国家的数据也显示在图中了,但是这不是我想要的效果啊,干脆把那个参数改为了不连续,结果四个国家的数据没有对应了,后来通过pieces参数调整过来了,并且达到了自己想要的效果。

    visualMap: {
      type: 'piecewise',
      left:30,
      realtime: false,
      calculable : true,
      pieces: [
        {gte: 100, label: '范围4', symbol: 'circle', color: '#ff523f'},
        {gte: 10, lte: 100, label: '范围3', symbol: 'circle', color: '#fab011'},
        {gte: 1, lte: 9, label: '范围2', symbol: 'circle', color: '#ffe100'},
        {lt: 1,  label: '范围1', symbol: 'circle', color: '#67cc02'}
      ],
    },

如果你也是使用官方提供的demo实现的中国地图,那么会发现,series里面有两个对象,另外加上geo,相当于有三个对象。其实用这三个中的一个,就能将中国地图展示出来,你可以试一下,我只试了两个对象。

右侧放大缩小按钮来控制地图缩放

这个比较容易实现,关键可能是调用地图的api,来实现他的放大缩小,具体代码如下:

<div v-if="!loading" class="button-wrapper">
      <el-button
        size="small"
        class="button-grow"
        :disabled="currentZoom > 3"
        @click="roamMap(0)"
      >
        <i class="iconfont icon-fangda" />
      </el-button>
      <el-button
        size="small"
        class="button-shrink"
        :disabled="currentZoom < 1"
        @click="roamMap(1)"
      >
        <i class="iconfont icon-suoxiao" />
      </el-button>
    </div>
    
    // 地图缩放 flag: 0->放大 1->缩小
    roamMap(flag) {
      this.currentZoom = this.$refs.worldMapChart.chart.getOption().series[0].zoom; // 当前的缩放比例
      let increaseAmplitude = 1.2; // 点击按钮每次 放大/缩小 比例
      if (flag == 1) {
        increaseAmplitude = 0.8;
      }
      this.initOption.series[0].zoom = this.currentZoom * increaseAmplitude;
      this.$refs.worldMapChart.chart.setOption(this.initOption);
    },

世界地图上点击任何一个国家,会显示黄色,调整该颜色

其实在最初,没有找到对应的配置项,最后的最后才发现,唉,Echarts想的还是很全面的,想要实现的内容一定,去找配置项,耐心找。 在series中添加下述代码即可:

select: {
  label: {
    // 不显示国家名称
    show: false
  },
  itemStyle: {
    // 这里可以设置个颜色覆盖掉默认的黄色
    areaColor: '#F7F7F7'
  }
},

其实在最初找到了一种方案,可以试一下:

// 点击某个国家后,原本默认会显示黄色,现在调整一下
  this.$refs.worldMapChart.chart.on('click', function(params) {
    if (params?.event?.target?.states?.select?.style) {
      params.event.target.states.select.style.fill = params.color ? params.color : '#F7F7F7';
    }
  });

点击图例后,图例颜色会变浅,做调整

这个也是,有对应api,但是我最初在实现的时候,用了一个笨方法,把原本的图例设置为隐藏,然后写了一个div,覆盖在上面,保证图例无法点击,因为我们的需求其实是不需要点击的。

<div v-if="!loading" class="legend-wrapper">
  <el-badge color="#B32424">
    <span>范围4</span>
  </el-badge>
  <el-badge color="#FF3333">
    <span>范围3</span>
  </el-badge>
  <el-badge color="#FF9F40">
    <span>范围2</span>
  </el-badge>
  <el-badge color="#FFCB48">
    <span>范围1</span>
  </el-badge>
</div>

调整世界地图默认的颜色:

itemStyle: {
  // 区域的颜色
  areaColor: '#F7F7F7',
  // 边框的颜色
  borderColor: '#D0D0D0',
  // 鼠标悬浮时,选中区域的颜色(默认会显示当前区域展示的颜色)
  emphasis: {
    areaColor: '#a4edba',
  }
}

鼠标悬浮,不在地图上展示国家名称,而是在tooltip中显示:

// 鼠标悬浮的时候,不单独显示国家名称
emphasis: {
  label: {
    show: false
  }
},

基于之前封装的组件,在世界地图完整代码如下:

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

至此,世界地图就完整地呈现出来了。