Skip to content

前端基于shp地图数据生成路径点地图

一般省级市级地图数据我们可以通过各种地图工具较为轻易的提取,但如果涉及到乡镇级的地图,通常来讲保密程度会比较高,地图工具不会直观的提供给你,而网上提供的多为shp格式的地图数据,这里我们可以使用一个mapshaper这个工具网站将shp格式转化为我们需要的json

阿里云数据可视化平台

mapshaper

导出的json一般为如下格式

json
{
  "type": "GeometryCollection",
  "geometries": [
    {
      "type": "Polygon",
      "coordinates": [
        [
          [116.64977017, 28.96650577],
          [116.65436517, 28.96539679],
          ...
        ]
      ]
    },
    {
      "type": "Polygon",
      "coordinates": [
        [
          [116.77645317, 29.41624014],
          [116.77658917, 29.41628714],
          ...
        ]
      ]
    }
    ...
  ]
}

这个格式无法被echart的map类型图表直接使用,我们需要将数据重新格式化,生成下方的格式

json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "鄱阳镇"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [116.64977017, 28.96650577],
            [116.65436517, 28.96539679],
            ...
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "name": "凰岗镇"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [116.77645317, 29.41624014],
            [116.77658917, 29.41628714],
            ...
          ]
        ]
      }
    },
  ]
}

我们将新的json数据导入echart,就生成了一张乡镇级别精度的地图

javascript
<template>
    <div class="map-container" ref="mapContainer"></div>
</template>

<script>
import * as echarts from 'echarts';
import geoJson from '@/assets/map/poyang.json';

export default {
    mounted() {
        this.initMap();
    },
    methods: {
        initMap() {
            // 创建地图实例
            const mapContainer = this.$refs.mapContainer;
            const chart = echarts.init(mapContainer);

            echarts.registerMap('poyang', geoJson);

            // 设置地图配置项
            const option = {
                geo: {
                    map: 'poyang',
                    show: true,
                    roam: true, // 地图是否支持缩放和平移
                    center: [116.78284549760457, 29.230851059087044],
                    zoom: 1, //当前视角缩放比例
                    label: {
                        normal: { // 文字的默认样式
                            show: true,
                            textStyle: {
                                color: '#fff'
                            }
                        },
                        emphasis: { // 文字的激活样式
                            show: true,
                            textStyle: {
                                color: '#fff'
                            }
                        }
                    },
                    itemStyle: {
                        normal: { // 地图区域的默认样式
                            areaColor: '#3a7fd5',
                            borderColor: '#0a53e9', //线
                            shadowColor: '#092f8f', //外发光
                            shadowBlur: 20
                        },
                        emphasis: { // 地图区域的激活样式
                            areaColor: '#0a2dae' //悬浮区背景
                        }
                    }
                }
            };
            chart.setOption(option);
        }
    }
};
</script>

<style scoped>
.map-container {
    width: 100%;
    height: 100%;
}
</style>

效果如下图:

image.png

如果你的需求只是生成一张这样的平面图的话,那到这里就已经完成了

但有的时候需求会要求设计出一些视觉效果更为复杂,或是对地图进行一些旋转/倾斜视角等变化,echart就无法满足这类效果的实现了

我们需要将这张地图进行处理,生成UI可以直接转化为路径点的图片

首先我们去掉背景、每个区域的边界颜色、文字等要素,同时给每个区域添加对比度比较强的填充,生成新的echart地图

javascript
// 设置地图配置项
const option = {
  geo: {
    map: 'poyang',
    show: true,
    roam: true, // 地图是否支持缩放和平移
    center: [116.78284549760457, 29.230851059087044],
    zoom: 1, // 当前视角缩放比例
    itemStyle: {
      normal: {
        borderColor: 'transparent' // 线
      }
    }
  },
  regions: [
    { name: '鄱阳镇', itemStyle: { areaColor: '#673ab7' } },
    { name: '谢家滩镇', itemStyle: { areaColor: '#f00' } },
    { name: '石门街镇', itemStyle: { areaColor: '#00f' } },
    { name: '四十里街镇', itemStyle: { areaColor: '#0ff' } },
    { name: '油墩街镇', itemStyle: { areaColor: '#f0f' } },
    { name: '田畈街镇', itemStyle: { areaColor: '#ff9800' } },
    { name: '金盘岭镇', itemStyle: { areaColor: '#0f0' } },
    { name: '高家岭镇', itemStyle: { areaColor: '#f00' } },
    { name: '凰岗镇', itemStyle: { areaColor: '#00f' } },
    { name: '双港镇', itemStyle: { areaColor: '#ff9800' } },
    { name: '古县渡镇', itemStyle: { areaColor: '#ff9800' } },
    { name: '饶丰镇', itemStyle: { areaColor: '#ff0' } },
    { name: '乐丰镇', itemStyle: { areaColor: '#0f0' } },
    { name: '饶埠镇', itemStyle: { areaColor: '#f00' } },
    { name: '侯家岗乡', itemStyle: { areaColor: '#00f00f' } },
    { name: '莲花山乡', itemStyle: { areaColor: '#0ff' } },
    { name: '响水滩乡', itemStyle: { areaColor: '#ff9800' } },
    { name: '枧田街乡', itemStyle: { areaColor: '#ff0' } },
    { name: '柘港乡', itemStyle: { areaColor: '#0f0' } },
    { name: '鸦鹊湖乡', itemStyle: { areaColor: '#f00' } },
    { name: '银宝湖乡', itemStyle: { areaColor: '#00f' } },
    { name: '游城乡', itemStyle: { areaColor: '#0ff' } },
    { name: '珠湖乡', itemStyle: { areaColor: '#f0f' } },
    { name: '白沙洲乡', itemStyle: { areaColor: '#ff0' } },
    { name: '团林乡', itemStyle: { areaColor: '#0f0' } },
    { name: '昌洲乡', itemStyle: { areaColor: '#f00' } },
    { name: '庙前乡', itemStyle: { areaColor: '#00f' } },
    { name: '莲湖乡', itemStyle: { areaColor: '#0ff' } },
    { name: '芦田乡', itemStyle: { areaColor: '#f0f' } },
    { name: '农科所', itemStyle: { areaColor: '#ff0' } }
  ]
}

效果如下:

image.png

将这张图发给UI,UI通过Adobe AI工具根据每个区域的色值区分范围生成路径点图片,将其导出为svg文件,我们就得到了所需要的路径点path标签的集合

我们使用svg的gpath 标签构建我们的路径点图形,并给图形加上交互样式

g标签是SVG中的分组(group)元素,用于将多个SVG元素进行组合。它仅仅作为一个容器元素,如果你追求代码的简洁,将相关的样式、操作属性绑定在path上也是可以的,但使用g标签整体的维护性和拓展性会更强一些

javascript
<template>
    <div class="test-map-container">
        <svg viewBox="0 0 596 669">
            <!-- 如果有背景图,可以使用最外层g标签的translate属性控制路径点图形组的偏移以匹配背景图 -->
            <g transform="translate(-26,-100)">
                <g class="mapItem mapPoint" id="响水滩乡">
                    <path
                        class="mapPath"
                        fill="none"
                        d="M278.6,100.2c0.6,0.4......100.2z"
                    />
                </g>
                <g class="mapItem mapPoint" id="响水滩乡">
                    <path
                        class="mapPath"
                        fill="none"
                        d="M278.6,100.2......100.2z"
                    />
                </g>
                ...
            </g>
        </svg>
    </div>
</template>

<script>
export default {
    name: 'Map'
};
</script>

<style scoped lang="less">
.test-map-container {
    position: absolute;
    margin: auto;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    width: 596px;
    height: 669px;
    overflow: hidden;
}
.mapItem {
    &.mapPoint {
        cursor: pointer;
        .mapPath { // 默认样式
            fill: rgba(235, 178, 95, 0.2);
            stroke: rgba(235, 178, 95, 1);
        }
        &:hover { // hover效果
            .mapPath {
                fill: rgba(235, 178, 95, 0.5);
                stroke: rgba(235, 178, 95, 1);
            }
        }
        &.selected { // 点击效果
            .mapPath {
                fill: rgba(235, 178, 95, 1);
                stroke: rgba(235, 178, 95, 1);
            }
        }
    }
}
</style>

效果如下: 20d2 image.png

我们也可以给路径点添加背景图、路径的阴影效果、点击事件等等,达成更为丰富的效果

image.png

参考项目:

鄱阳纪委数据大屏

信州区智慧物业管理服务平台


最后更新于:2023-07-21