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

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

效果图:

准备

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/...

相关推荐
.生产的驴1 分钟前
Electron Vue框架环境搭建 Vue3环境搭建
java·前端·vue.js·spring boot·后端·electron·ecmascript
awonw4 分钟前
[前端][easyui]easyui select 默认值
前端·javascript·easyui
九圣残炎25 分钟前
【Vue】vue-admin-template项目搭建
前端·vue.js·arcgis
柏箱1 小时前
使用JavaScript写一个网页端的四则运算器
前端·javascript·css
TU^1 小时前
C语言习题~day16
c语言·前端·算法
学习使我快乐014 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19954 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈5 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水6 小时前
简洁之道 - React Hook Form
前端