美文网首页
echarts 自定义地图数据

echarts 自定义地图数据

作者: 头上有煎饺 | 来源:发表于2022-01-06 16:52 被阅读0次

    1. 地图数据来源

    echarts仓库里面就有,地图数据不会经常改变,没必要在线获取,还慢
    地图数据有jsonjs格式的,jsonecharts压缩过的,js本质就是引入json只是包装了导出

    2. 整形工具

    最重要的部分就是利用工具处理这些数据,实现如扣去某块区域添加某块区域去除边界等功能

    1. echarts-mapmaker压缩解码地图数据、合并拆分地图数据
    2. mapshaper整形地图,主要就是来去除边界
    3. 文档,上面有例子
    4. 这个仓库也有很多新的地图数据,自己可以翻看

    3. 实战

    3.1 拆分地图区域

    这里我们拆分重庆各个区县为例

    const path = require('path')
    const fs = require('fs')
    const fsp = require('fs/promises')
    const distFolder = path.resolve(__dirname, './dist')
    const dest = (fileName) => {
      try {
        fs.accessSync(distFolder, fs.constants.W_OK)
      }catch(err) {
        fs.mkdirSync(distFolder)
      }
      return path.resolve(__dirname, distFolder, fileName)
    }
    
    // 引入mapmaker
    const maker = require('echarts-mapmaker/src/maker')
    // 引入原始地图数据
    const chongqingJson = path.resolve(__dirname, './map/province/chongqing.json')
    // 解码地图数据并输出
    // 解码后的文件就是GeoJson 方便后续操作
    const dec_chonggqing = dest('dec_chongqing.json')
    maker.decompress(chongqingJson, dec_chonggqing)
    // 分割区域
    maker.splitAsGeojson(dec_chonggqing, distFolder)
    
    解码后的文件
    分割后的文件(名称是自动根据json里面的name生成的)

    3.2 合并区域

    比如我需要合并中部地区、西部地区之类的,就需要合并区域

    // 只需要这一句话
    // 合并第一个和第二个json
     maker.merge('./dist/九龙坡区.geojson', './dist/大渡口区.geojson')
    
    根目录输出文件

    这个方法有些问题:

    1. 无法自定义输出位置和输出文件名
    2. 每合并一次输出文件前面会加一个merge_,处理起来很麻烦
      可以考虑自己写一个方法,参考源码其实不难(最好还是了解一下geojson
    // 源码
    function merge(geojson, geojsonToBeMerged){
      // 读取两个文件
      const data = fs.readFileSync(geojson, 'utf8');
      const data2 = fs.readFileSync(geojsonToBeMerged, 'utf8');
      var parent = JSON.parse(data);
      var child = JSON.parse(data2);
      
      // features要素,就是描述边界信息的一个数组
      child.features.forEach(function(feature){
        // 只合并不同name的区域
        parent.features = parent.features.filter((featurex)=>{
          return featurex.properties.name!==feature.properties.name;
        });
        // 直接把一个数据的边界信息放入另一个的features中
        parent.features.push(feature);
      });
      // 写入文件
      fs.writeFileSync('merged_'+path.basename(geojson), JSON.stringify(parent));
    }    
    

    逻辑很简单,主要就是提取要素然后放入另一个地图里面,下面是我简单的一个封装

    function mergeToOne(targetJSON, distDir, ...childrenJSONList){
      // 读取目标json,其他json都往这个json合并
      const data = fs.readFileSync(targetJSON, 'utf8');
      const parentData = JSON.parse(data);
      // 循环需要合并的数据
      childrenJSONList.forEach(child => {
        const childJSON= fs.readFileSync(child, 'utf8')
        const childData = JSON.parse(childJSON)
        // 合并
        childData.features.forEach(function(feature){
          parentData.features = parentData.features.filter((featurex)=>{
            return featurex.properties.name!==feature.properties.name;
          });
          parentData.features.push(feature);
        });
      })
    
      // 写文件
      fs.writeFileSync(distDir, JSON.stringify(parentData));
    }
    
    // 使用
    // 最后会输出一个`合并文件.json`,合并了三个区
    mergeToOne('./dist/九龙坡区.geojson', './合并文件.json', './dist/大渡口区.geojson', './dist/沙坪坝区.geojson')
    

    3.3 镶嵌区域

    只用合并也可以,但是在echarts中看起来就不大一样,使用合并高亮地图的时候看起来不是一体的,还有其他区别自行确认。
    所以还要结合扣去区域cut

    // 使用 
    maker.cut('a.json', '重庆', '沙坪坝区')
    

    但是源码似乎有问题,反正我用开头给的地图数据是无法正确切除的

    // 源码
    var cutAHoleInFeatureAWithFB = (jsonFile, featureA, featureB) => {
    
      data = fs.readFileSync(jsonFile, 'utf8');
    
      var geojson = JSON.parse(data);
      var featurea = geojson.features.find(feature => feature.properties.name === featureA);
      var featureb = geojson.features.find(feature => feature.properties.name === featureB);
      // https://stackoverflow.com/questions/43645172/geojson-multipolygon-with-multiple-holes
    // 就是这一步 似乎不正确
      featurea.geometry.coordinates.push(featureb.geometry.coordinates[0]);
    
      fs.writeFileSync("cut_" + jsonFile, JSON.stringify(geojson));
    };
    

    查阅资料发现,geojson挖去孔洞就是使用MultiPolygon要素,
    多边形带空洞的数据格式是一个四维数组,

    {
          "type": "Feature",
          "properties": {},
          "geometry": {
            "type": "MultiPolygon",
            "coordinates":
        [ 
            [
                [
                  // 这个就是孔洞的多边形数据
                    [101.6455078125,27.68352808378776],
                    [114.78515624999999,27.68352808378776],
                    [114.78515624999999,35.209721645221386],
                    [101.6455078125,35.209721645221386],
                    [101.6455078125,27.68352808378776]
                ],
                [
                    [104.2822265625,30.107117887092357],
                    [108.896484375,30.107117887092357],
                    [108.896484375,33.76088200086917],
                    [104.2822265625,33.76088200086917],
                    [104.2822265625,30.107117887092357]
                
                ]
            ]
        ]
       }
    }
    
    // 再简化
    {
      "type": "MultiPolygon",
      "coordinates": [
        [
          {polygon},
          {hole},
          {hole},
          {hole}
        ]
      ]
    }
    

    源码的问题就是

     // coordinates层级错了
      featurea.geometry.coordinates.push(featureb.geometry.coordinates[0]);
    // 改为
    featurea.geometry.coordinates[0].push(featureb.geometry.coordinates[0]);
    

    下面是我修改后的

    var cutArea = (jsonFile, featureA, featureB) => {
    
      data = fs.readFileSync(jsonFile, 'utf8');
    
      var geojson = JSON.parse(data);
      var featurea = geojson.features.find(feature => feature.properties.name === featureA);
      var featureb = geojson.features.find(feature => feature.properties.name === featureB);
      featurea.geometry.coordinates[0].push(featureb.geometry.coordinates[0])
      fs.writeFileSync("cut_" + jsonFile, JSON.stringify(geojson));
    }
    

    所以镶嵌的过程就是:

    1. 合并两个地图
    2. 扣去镶嵌的区域
    mergeToOne('./dist/d_china.json', './合并文件.json', './dist/沙坪坝区.geojson')
    cutArea('合并文件.json', '重庆', '沙坪坝区')
    

    3.4 消除内部边界

    主要用到mapshaper,挺复杂的一个东西,有时间可以详细研究

    const maker = require('echarts-mapmaker/src/maker')
    const shaper = require('mapshaper')
    shaper.runCommands('./dist/d_chongqing.json  -dissolve2 -o chongqing_shape_only.geojson', (err) => {
      if(!err) {
        maker.transform('./chongqing_shape_only.geojson', './chongqing_shape_only.echarts.json', '重慶市')
      }
    })
    
    1. 主要利用mapshaperdissolve2命令
    2. 去除边界完成后echarts不能直接使用,要用mapmaker转化一次,这里和挂网的文档不一样注意使用transform方法
    3. 官网文档使用的是全局安装mapshaper然后用命令行,我这里用的是wiki上的变成方式,本质上也是命令行。

    4 总结

    以上就是基本的一些操作,通过结合上面的基本方法,我们可以随意组合想要的地图数据。

    相关文章

      网友评论

          本文标题:echarts 自定义地图数据

          本文链接:https://www.haomeiwen.com/subject/iqtwtrtx.html