高德地图实现点击特定省份高亮某条高速公路并且标出该条高速公路上的服务区

需求背景:在高德地图上实现点击高亮安徽省境内的任一条高速公路且需要展示出沿途的服务区

效果图:

准备

1. 成为高德地图开发者并创建 key

先注册成为高德开放平台开发者,并申请 web 平台(JS API)的 key 和安全密钥(这一步不多做叙述,详细看高德官网)

提示:2021年12月02日以后申请的 key 需要配合你的安全密钥一起使用。

2. 引入高德地图

js 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title></title>
    <script type="text/javascript">
      window._AMapSecurityConfig = {
        securityJsCode: "您的高德安全密钥",
      };
    </script>
    <script src="https://webapi.amap.com/maps?v=2.0&key=7c6bc75bf40b761c056521cc4434f6cd&plugin=AMap.GeoJSON,AMap.Geocoder,AMap.PlaceSearch"></script>
    <script src="https://webapi.amap.com/loca?v=2.0.0&key=您的高德key"></script>
    <style>
      html,
      body,
      #map {
        width: 100%;
        height: 100%;
        margin: 0;
        padding: 0;
      }

      .amap-logo {
        display: none !important;
      }

      .amap-copyright {
        display: none !important;
      }

      .custom-input-card {
        width: 18rem;
      }

      .custom-input-card .btn:last-child {
        margin-left: 1rem;
      }

      .content-window-card {
        position: relative;
        width: 23rem;
        padding: 0.75rem 0 0 1.25rem;
        box-shadow: none;
        bottom: 0;
        left: 0;
      }

      .content-window-card p {
        height: 2rem;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      let map = new AMap.Map("map", {
        zoom: 8,
        center: [117.227267, 31.420567],
        mapStyle: "amap://styles/8694fc8103d0cbe15eb70b8308cd4171",
        viewMode: "3D",
        pitch: 50,
        fitView: true,
        labelzIndex: 111,
      });

      var distProvince = new AMap.DistrictLayer.Province({
        zIndex: 10, //设置图层层级
        zooms: [2, 15], //设置图层显示范围
        adcode: "340000", //设置行政区 adcode
        depth: 0, //设置数据显示层级,0:显示国家面,1:显示省级,当国家为中国时设置depth为2的可以显示市一级
      });

      // 设置行政区图层样式
      distProvince.setStyles({
        "stroke-width": 2, //描边线宽
        "province-stroke": "#ff714d", //描边颜色
        fill: "rgba(0,0,0,0.3)",
      });

      map.add(distProvince);
    </script>
  </body>
</html>

3. 利用overpass-turbo获取安徽省境内高速、服务区的geojson

打开overpass-turbo网站,输入查询语句(由于数据有点大,我把高速公路和服务区的查询分两次查询和导出)

3.1 查询高速公路数据

输入查询语句

sql 复制代码
[out:json];
area["name"="安徽省"]->.a;
(
  way["highway"="motorway"](area.a);
  way["highway"="motorway_link"](area.a);
);
out body;
>;
out skel qt;

3.2 查询服务区数据

输入查询语句

sql 复制代码
[out:json];
area["ISO3166-2"="CN-AH"]->.a;
(
  way(area.a)[highway=services];
);
(._;>;);
out body;

什么?你不会写这个语句!没关系,有万能的chatgpt,就像这样,拷贝下来粘贴到overpass-turbo语句输入框然后执行

至此我们已经得到高速公路(highway.geojson)和高速服务区(services.geojson)两个geojson文件了,可以愉快的写代码了

实现

1. 给高德地图添加点击事件

js 复制代码
map.on('click', function (ev) {})

2. 利用高德逆向地理编码能力获取点击位置道路信息

js 复制代码
map.on('click', function (ev) {
    let geocoder = new AMap.Geocoder({
        city: '340000', //设为安徽,默认:"全国"
        radius: 1000, //范围,默认:500
    })
    geocoder.getAddress([ev.lnglat.lng, ev.lnglat.lat], function (status, res) {
        if (status === 'complete' && res.regeocode) {
            console.log('道路信息:', res.regeocode.formattedAddress);
            if (res.regeocode.formattedAddress.includes('高速')) {
              // 过滤高速编号
              const regex = /[A-Z]\d+(?=[\u4e00-\u9fa5]+高速)/ // 匹配一个大写字母后跟一个或多个数字,但要求其后必须紧跟着中文字符和"高速"字符
              const result = res.regeocode.formattedAddress.match(regex)

              // 匹配高速名称
              const highwayRegex = /([\u4e00-\u9fa5]+)(高速)/
              const match = res.regeocode.formattedAddress.match(highwayRegex)
              const highwayName = match[1] + match[2]
              console.log('匹配到的高速名称:', highwayName)
            }
        }
    })
})

3. 加载高速公路geojson并匹配上面获取到的高速编号

js 复制代码
// 加载高速geojson
fetch('./highway.geojson').then((response) => {
  return response.json()
}).then((geoJSON) => {
  // 匹配高速编号并且是LineString的要素后添加到相应的数组
  const desiredHighways = []
  for (let i = 0; i < geoJSON.features.length; i++) {
    if (geoJSON.features[i].properties.ref) {
      let wayRefs = geoJSON.features[i].properties.ref.split(';')
      for (let j = 0; j < wayRefs.length; j++) {
        if (wayRefs[j] == result[0] && geoJSON.features[i].geometry.type == 'LineString') {
          // console.log(wayRefs[j]);
          desiredHighways.push(geoJSON.features[i])
        }
      }
    }
  }

4. 添加高亮线

js 复制代码
// 添加高亮线
for (let i = 0; i < desiredHighways.length; i++) {
    //创建 Polyline 实例
    let polyline = new AMap.Polyline({
      path: desiredHighways[i].geometry.coordinates,
      isOutline: false,
      outlineColor: '#ffeeff',
      borderWeight: 2,
      strokeColor: '#1677ff',
      strokeOpacity: 1,
      strokeWeight: 3,
      // 折线样式还支持 'dashed'
      strokeStyle: 'solid',
      // strokeStyle是dashed时有效
      // strokeDasharray: [10, 5],
      zIndex: 49,
      lineJoin: 'round',
      lineCap: 'round',
    })
    map.add(polyline)
}

至此实现了点击高亮某一条高速公路

5. 加载服务区geojson,匹配上面获取到的高速公路名称后向地图上添加服务区图形

js 复制代码
// 加载高速服务区
fetch('./services.geojson').then((response) => {
  return response.json()
}).then((geoJSON) => {
  let geojson = new AMap.GeoJSON({
    geoJSON: geoJSON,
    getPolygon: function (json, lnglats) {
      if (json.properties.extraData.formattedAddress.includes(highwayName)) {
        let polygon = new AMap.Polygon({
          path: lnglats,
          strokeColor: '#ffd666',
          strokeWeight: 6,
          strokeOpacity: 0.4,
          fillOpacity: 0.4,
          fillColor: '#95de64',
          zIndex: 50,
          extData: json.properties,
        })
        polygon.on('click', function (e) {
          console.log('click', this.getExtData())
          polygonClick(e, this.getExtData())
        })
        return polygon
      } else {
        return []
      }
    },
    // getPolygon: function () {
    //   return [];
    // },
    getMarker: function (geojson, lnglats) {
      return []
    },
  })
  // 添加geojson图层
  map.add(geojson)
})

注意

1. 坐标转换

由于overpass-turbo上面导出的geojson坐标是坐标是WGS84,而高德是GCJ02,所以需要坐标系转换

2. 处理服务区geojson

直接导出的geojson服务区信息没有那么全,所以我使用了高德批量逆向地理编码逐个查询了geojson中的服务区详细信息,然后再将原本的geojson和从高德api获取的数据进行合并处理

完整代码

demo完整源码已经上传到github有需要的可以自取

github.com/jinfei-lab/...

相关推荐
M_emory_5 分钟前
解决 git clone 出现:Failed to connect to 127.0.0.1 port 1080: Connection refused 错误
前端·vue.js·git
Ciito8 分钟前
vue项目使用eslint+prettier管理项目格式化
前端·javascript·vue.js
成都被卷死的程序员41 分钟前
响应式网页设计--html
前端·html
mon_star°1 小时前
将答题成绩排行榜数据通过前端生成excel的方式实现导出下载功能
前端·excel
Zrf21913184551 小时前
前端笔试中oj算法题的解法模版
前端·readline·oj算法
文军的烹饪实验室2 小时前
ValueError: Circular reference detected
开发语言·前端·javascript
Martin -Tang3 小时前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发3 小时前
解锁微前端的优秀库
前端
王解4 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁4 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis