你一定会用得上的炫酷大屏地图效果

avatar

ECharts 散点图(Scatter)结合高德地图(AMap)和自定义地理数据(GeoJSON), 打造出炫酷的大屏地图效果

setCur1.gif

如何绘制自定义地图

ECharts 支持在 地理坐标系(geo) 和 地图系列(map series) 中使用 SVG 或者 GeoJSON 作为底图。

如何编辑自定义地图

DataV.GeoAtlas地理小工具系列可以获取到省/市/县轮廓图的数据, 将其他类型中的内容复制到 geojson.io, 即可编辑地图, 包括调整区块, 增加标记等等, 还提供表格模式, 可以很方便地编辑数据.

注意: 由于在 geojson.io 中使用的是国外的地图服务(OpenStreetMap), 标记的元素要在高德地图上显示时, 需要转成国标, 或者考虑在 DataV.GeoAtlas 提供的边界生成器中编辑数据

image.png

image.png

如何渲染自定义地图

数据编辑好后, 将 GeoJSON 保存下来, 再通过 ECharts 就可以渲染出地图了

echarts.registerMap('mapName', {
  "type":"FeatureCollection",
  "features":[]
});
option = {
  geo: {
    map: 'mapName',
  }
};
myChart.setOption(option);

结合高德地图

通过 echarts-extension-amap 我们可以让 ECharts 与高德地图结合在一起

结合自定义地理数据

我们先尝试通过渲染自定义地图的方式和高德地图结合在一起

echarts.registerMap('cs', {
  "type":"FeatureCollection",
  "features":[]
});
const option = {
  amap: {
    viewMode: '3D',
    resizeEnable: true,
    renderOnMoving: true,
    echartsLayerZIndex: 2000,
    echartsLayerInteractive: true,
    largeMode: false
  },
  series: [
    {
      type: 'map',
      map: 'cs',
      roam: true,
    },
  ]
};

myChart.setOption(option);

但发现这种方式不能很好地结合, 主要的问题如下

  1. 位置存在偏移
  2. 自定义地图无法随高德地图联动
    • 当设置 roam:false 时拖动高德地图, 自定义地图不会动
    • 当设置 roam:true 时自定义地图是可以拖动了, 但只是单纯的拖动他自己, 与高德地图的拖动是完全独立的, 即拖动自定义地图时, 高德地图不动; 拖动高德地图时, 自定义地图又不动

因此我们改用 AMap.GeoJSON 的方式将 GeoJSON 绘制到高德地图上

const aMapGeoJson = new AMap.GeoJSON({
  geoJSON: geojson,
  getPolygon: function(geojson, lnglats) {
    return new AMap.Polygon({
      path: lnglats,
      fillOpacity: 0.6,
      strokeColor: '#DCDFE6',
      fillColor: '#409EFF',
    });
  }
});
aMapGeoJson.setMap(amap);

结合散点图

最后通过 effectScatter 绘制散点(气泡)图, 注意将 coordinateSystem 设置为 amap

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>ECharts 散点图(Scatter)结合高德地图(AMap)和自定义地理数据(GeoJSON)</title>
</head>
<body style="margin: 0;">
  <div id="main" style="width: 100vw; height: 100vh;"></div>
  <script src="https://webapi.amap.com/maps?v=1.4.4&key={替换成你的KEY}"></script>
  <script src="https://unpkg.com/echarts@5.4.3/dist/echarts.min.js"></script>
  <script src="https://unpkg.com/echarts-extension-amap@1.11.0/dist/echarts-extension-amap.min.js"></script>
  <script>
    const myChart = echarts.init(document.getElementById('main'));

    // 替换成你的 GeoJSON 格式的自定义地理数据
    const geojson = {"type":"FeatureCollection","features":[]}

    const option = {
      title: {
        text: 'ECharts 散点图(Scatter)结合高德地图(AMap)和自定义地理数据(GeoJSON)',
        subtext: 'ECharts + AMap + GeoJSON + Scatter',
      },
      // 结合高德地图
      amap: {
        // enable 3D mode
        // Note that it's suggested to enable 3D mode to improve echarts rendering.
        viewMode: '3D',
        // initial options of AMap
        // See https://lbs.amap.com/api/javascript-api/reference/map#MapOption for details
        resizeEnable: true,
        // customized map style, see https://lbs.amap.com/dev/mapstyle/index for details
        // https://lbs.amap.com/api/javascript-api/guide/map/map-style/
        // mapStyle: 'amap://styles/dark',
        // whether echarts layer should be rendered when the map is moving. Default is true.
        // if false, it will only be re-rendered after the map `moveend`.
        // It's better to set this option to false if data is large.
        renderOnMoving: true,
        // the zIndex of echarts layer for AMap, default value is 2000.
        // deprecated since v1.9.0, use `echartsLayerInteractive` instead.
        echartsLayerZIndex: 2000,
        // whether echarts layer is interactive. Default value is true
        // supported since v1.9.0
        echartsLayerInteractive: true,
        // whether to enable large mode. Default value is false
        // supported since v1.9.0
        largeMode: false
      },

      series: [
        // 结合散点图
        {
          type: 'effectScatter',
          coordinateSystem: 'amap',
          symbolSize: function (params) {
            return (params[2] / 100) * 15 + 5;
          },
          itemStyle: {
            color: '#b02a02'
          },
          label: {
            formatter: '{b}',
            show: true,
          },
          data: [
            {
              name: 'demo',
              value: [112.95905621695658, 28.21745411105819, 100],
            }
          ]
        }
      ]
    };

    myChart.setOption(option);

    // get AMap extension component
    const amapComponent = myChart.getModel().getComponent('amap');
    // get the instance of AMap
    const amap = amapComponent.getAMap();

    // 结合 GeoJSON
    // 将 geojson 绘制到地图上
    // https://lbs.amap.com/demo/javascript-api/example/overlayers/geojson
    const aMapGeoJson = new AMap.GeoJSON({
      geoJSON: geojson,
      getPolygon: function(geojson, lnglats) {
        return new AMap.Polygon({
          path: lnglats,
          fillOpacity: 0.6,
          strokeColor: '#DCDFE6',
          fillColor: '#409EFF',
        });
      }
    });
    aMapGeoJson.setMap(amap);

    // 根据地图上添加的覆盖物分布情况,自动缩放地图到合适的视野级别
    amap.setFitView();
  </script>
</body>
</html>

参考