echarts 双层 geo 地图同步拖动

每次写之前没碰到过的需求时都有“臣妾做不到”的烦恼。在 echarts 的示例中,可以找到很多双层 geo 的例子,但是难以找到可同步拖动的。不管怎样,先把双层 geo 搞出来。

双层 geo

geo: [
  // 底图
  {
    id: 'base',
    map: mapCode,
    animation: false,
    roam: true,
    silent: true,
    layoutCenter: ['51%', '51%'],
    layoutSize: '100%',
    tooltip: {
      show: false,
    },
    scaleLimit: {
      min: 1,
      max: maxZoom,
    },
    center: this.center.length ? this.center : undefined,
    zoom: this.zoom,
    label: {
      show: false,
    },
    itemStyle: {
      areaColor: 'rgba(0, 162, 255, 0.17)',
      borderColor: 'rgba(0, 162, 255, 1)',
      borderWidth: 0,
    },
  },
  {
    id: 'map',
    map: mapCode,
    animation: false,
    zlevel: 2,
    roam: true,
    layoutCenter: ['50%', '50%'],
    layoutSize: '100%',
    tooltip: {
      show: false,
    },
    scaleLimit: {
      min: 1,
      max: maxZoom,
    },
    center: this.center.length ? this.center : undefined,
    zoom: this.zoom,
    label: {
      show: false,
    },
    itemStyle: {
      areaColor: {
        image: this.dotImage,
        repeat: 'repeat',
      },
      borderColor: 'rgba(0, 162, 255, 1)',
      borderWidth: 1.3,
    },
    emphasis: {
      label: {
        show: false,
        textStyle: {
          color: 'rgba(255,255,255,0.7)',
          fontSize: 14 * windowSize.widthScale,
        },
      },
      itemStyle: {
        areaColor: {
          image: this.hoverDotImage,
          repeat: 'repeat',
        },
        borderWidth: 1.6,
      },
    },
    regions:
      code && mapCache.get(code)
        ? mapCache
            .get(code)
            ?.features?.map((feature: GeoJSON.Feature) => {
              const igonre = feature.properties?.name === '_'
              return {
                name: feature.properties?.name ?? '',
                itemStyle: {
                  areaColor: igonre ? 'rgba(0,0,0,0)' : undefined,
                },
                label: {
                  show: !igonre,
                  color: 'rgba(0, 192, 255, 1)',
                  fontSize: 14 * windowSize.widthScale,
                },
                emphasis: {
                  label: {
                    show: !igonre,
                  },
                  itemStyle: {
                    areaColor: igonre ? 'rgba(0,0,0,0)' : undefined,
                  },
                },
              }
            })
        : [],
  },
],

第二层 geo 包含了 regions 的配置,顺便复制上来了。

同步拖动

关于同步拖动,根据网友写的 georoam 事件的监听,适配了 react。但是,卡爆了,并且拖动缓慢、中断。原因是,我把 center 和 zoom 放到了 state 里,这样 echarts(echarts-for-react) 可以及时响应,但不停更新也导致了卡顿。因此,不能借助于 react 的响应式设计,需要自己调用 echarts 实例更新。

const onEvents = {
  georoam: (params: any) => {
    let tempOption = this.el?.getOption()
    if (tempOption && params.componentType === 'geo') {
      const geo = (
        tempOption.geo as Array<echarts.EChartOption.Series>
      ).find((v) => v.id === params.geoId)
      this.center = (geo as any).center || []
      this.zoom = (geo as any).zoom
      ;(tempOption.geo as Array<echarts.EChartOption.Series>).map(
        (v: any) => {
          v.center = this.center
          v.zoom = this.zoom
        },
      )
      this.el?.setOption(tempOption)
    }
  },
}

如双层 geo 的配置所示,center 和 zoom 也会取 this.center 和 this.zoom 的值,所以当组件 render 的时候位置和缩放都与手动设置的相同,不会显得违和。


双层 geo 地图