arcgis for js实现平移立体效果

在web(GIS)开发中,利用 ArcGIS API for JavaScript 实现各种炫酷的地图效果是很常见的需求。本文将介绍如何使用 ArcGIS API for JavaScript 实现平移立体效果,通过加载边界线,根据边界线平移生成新的面,再将天地图高亮区域覆盖其上,从而达到独特的视觉效果。

效果图

实现思路

首先加载边界线,根据边界线平移生成新的面,再将天地图高亮区域覆盖其上。通过这种方式,我们可以在地图上创建出一种立体的平移效果,增强地图的视觉表现力。

实现步骤:

  1. 加载底图 :使用天地图的影像图和影像注记作为底图,通过WebTileLayerBasemap来实现。
  2. 创建地图视图 :使用MapView创建一个二维地图视图,设置初始的缩放级别和中心点坐标。
  3. 加载边界线 :通过GeoJSONLayer加载边界线数据,并设置其渲染样式。
  4. 生成平移面图层 :获取边界线的图形数据,利用 Turf.js 库进行平移操作,然后创建一个GraphicsLayer来显示平移后的面。
  5. 加载范围高亮图层 :创建一个GroupLayer,包含天地图的影像图、影像注记以及一个带有高亮颜色的GeoJSONLayer,将其覆盖在平移面图层之上。

实现代码

效果1

html 复制代码
<!DOCTYPE html>
<html lang="zn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>我不当帕鲁谁当帕鲁</title>

    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        background: #000;
      }
      * {
        margin: 0;
        padding: 0;
      }
      body {
        background: linear-gradient(135deg, rgb(0, 173, 152) 0%, rgba(0, 87, 77, 0.2) 100%);
        /* background: #000; */
      }

      #mapView {
        position: absolute;
        width: 100%;
        height: 100%;
      }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
    <link rel="stylesheet" href="https://js.arcgis.com/4.23/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.23/"></script>
  </head>
  <body>
    <div id="mapView"></div>

    <script>
      require([
        'esri/Map',
        'esri/views/MapView',
        'esri/Basemap',
        'esri/layers/WebTileLayer',
        'esri/layers/GroupLayer',
        'esri/layers/GeoJSONLayer',
        'esri/layers/GroupLayer',
        'esri/layers/GraphicsLayer',
        'esri/Graphic'
      ], function (
        Map,
        MapView,
        Basemap,
        WebTileLayer,
        GroupLayer,
        GeoJSONLayer,
        GroupLayer,
        GraphicsLayer,
        Graphic
      ) {
        var tiandituBaseUrl = 'http://{subDomain}.tianditu.gov.cn' // 天地图服务地址
        var token = 'b5a612fc171599a0f5c51aa03efd4948' // 私人天地图token, 地图加载不出来的话就换成自己的

        // 天地图底图
        var imgLayer = new WebTileLayer({
          urlTemplate:
            tiandituBaseUrl + '/DataServer?T=img_w/wmts&x={col}&y={row}&l={level}&tk=' + token,
          subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
          copyright: '天地图影像图'
        })
        var ciaLayer = new WebTileLayer({
          urlTemplate:
            tiandituBaseUrl +
            '/DataServer?T=cia_w?T=vec_c/wmts&x={col}&y={row}&l={level}&tk=' +
            token,
          subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
          copyright: '天地图影像注记'
        })

        var vecBasemap = new Basemap({
          baseLayers: [imgLayer, ciaLayer],
          title: '影像图',
          id: 'img_w',
          thumbnailUrl:
            'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/0/0/0'
        })

        // 初始化底图
        window.map = new Map({
          basemap: vecBasemap // 指定一个底图
          // basemap: 'dark-gray-vector'
        })

        // 创建2维视图
        let view = new MapView({
          container: 'mapView',
          map: map,
          zoom: 9, // 初始化级别
          center: [103.979921, 30.680738] // 初始化中心点坐标
        })

        // 添加点击
        view.on('click', function (e) {
          console.log('>>> 点击的坐标: ')
          console.log(`${e.mapPoint.longitude}, ${e.mapPoint.latitude}`)
        })

        view.when(async () => {
          // 背景颜色在CSS中设置

          /**
           * 实现思路
           * 1. 加载边界线
           * 2. 根据边界线进行平移, 创建平移面图层
           * 3. 最后加载范围高亮天地图 (让其层级高于平移面图层,将其覆盖)
           */

          // 边界线
          const boundaryLineLayer = new GeoJSONLayer({
            url: 'https://geo.datav.aliyun.com/areas_v3/bound/510100.json',
            outFields: ['*'],
            renderer: {
              type: 'simple',
              symbol: {
                type: 'simple-line',
                color: '#7BD6F4',
                width: 2
              }
            }
          })
          // map.add(boundaryLineLayer, 20)

          // 获取边界图形
          const { features } = await boundaryLineLayer.queryFeatures()
          const rings = features[0].geometry.rings // 拿到最大的区域坐标

          const poly = turf.polygon(rings) // 转为turf多边形

          // 向下平移
          const translatedPoly = turf.transformTranslate(poly, -6, 350)

          // 创建平移面图层
          const translationLayer = new GraphicsLayer({ title: '平移面图层' })

          const graphic = new Graphic({
            geometry: {
              type: 'polygon',
              rings: translatedPoly.geometry.coordinates[0]
            },
            symbol: {
              type: 'simple-fill',
              color: 'rgba(59,139,142,1)',
              style: 'vertical', // 填充竖线
              outline: {
                width: 1,
                color: '#7BD6F4'
              }
            }
          })
          translationLayer.add(graphic)

          // 范围内的高亮地图
          const areaLayer = new GroupLayer({
            layers: [
              imgLayer,
              ciaLayer,
              new GeoJSONLayer({
                url: 'https://geo.datav.aliyun.com/areas_v3/bound/510100.json',
                blendMode: 'destination-in',
                outFields: ['*'],
                renderer: {
                  type: 'simple',
                  symbol: {
                    type: 'simple-fill',
                    color: [227, 139, 79, 1]
                  }
                }
              })
            ]
          })

          // map.add(translationLayer, 1)
          // map.add(areaLayer, 10)
          // map.add(boundaryLineLayer, 20)

          map.add(translationLayer) // 先添加平移面图层
          map.add(areaLayer) // 再添加范围高亮图层
          map.add(boundaryLineLayer) // 最后添加边界线图层
        })
      })
    </script>
  </body>
</html>

效果2

html 复制代码
<!DOCTYPE html>
<html lang="zn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>我不当帕鲁谁当帕鲁</title>

    <style>
      html,
      body {
        width: 100%;
        height: 100%;
        background: #000;
      }
      * {
        margin: 0;
        padding: 0;
      }
      body {
        background: linear-gradient(135deg, rgb(0, 173, 152) 0%, rgba(0, 87, 77, 0.2) 100%);
        /* background: #000; */
      }

      #mapView {
        position: absolute;
        width: 100%;
        height: 100%;
      }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.5.0/turf.min.js"></script>
    <link rel="stylesheet" href="https://js.arcgis.com/4.23/esri/themes/light/main.css" />
    <script src="https://js.arcgis.com/4.23/"></script>
  </head>
  <body>
    <div id="mapView"></div>

    <script>
      require([
        'esri/Map',
        'esri/views/MapView',
        'esri/Basemap',
        'esri/layers/WebTileLayer',
        'esri/layers/GroupLayer',
        'esri/layers/GeoJSONLayer',
        'esri/layers/GroupLayer',
        'esri/layers/GraphicsLayer',
        'esri/Graphic'
      ], function (
        Map,
        MapView,
        Basemap,
        WebTileLayer,
        GroupLayer,
        GeoJSONLayer,
        GroupLayer,
        GraphicsLayer,
        Graphic
      ) {
        var tiandituBaseUrl = 'http://{subDomain}.tianditu.gov.cn' // 天地图服务地址
        var token = 'b5a612fc171599a0f5c51aa03efd4948' // 私人天地图token, 地图加载不出来的话就换成自己的

        // 天地图底图
        var imgLayer = new WebTileLayer({
          urlTemplate:
            tiandituBaseUrl + '/DataServer?T=img_w/wmts&x={col}&y={row}&l={level}&tk=' + token,
          subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
          copyright: '天地图影像图'
        })
        var ciaLayer = new WebTileLayer({
          urlTemplate:
            tiandituBaseUrl +
            '/DataServer?T=cia_w?T=vec_c/wmts&x={col}&y={row}&l={level}&tk=' +
            token,
          subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
          copyright: '天地图影像注记'
        })

        var vecBasemap = new Basemap({
          baseLayers: [imgLayer, ciaLayer],
          title: '影像图',
          id: 'img_w',
          thumbnailUrl:
            'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/0/0/0'
        })

        // 初始化底图
        window.map = new Map({
          basemap: vecBasemap // 指定一个底图
          // basemap: 'dark-gray-vector'
        })

        // 创建2维视图
        let view = new MapView({
          container: 'mapView',
          map: map,
          zoom: 9, // 初始化级别
          center: [103.979921, 30.680738] // 初始化中心点坐标
        })

        // 添加点击
        view.on('click', function (e) {
          console.log('>>> 点击的坐标: ')
          console.log(`${e.mapPoint.longitude}, ${e.mapPoint.latitude}`)
        })

        view.when(async () => {
          // 背景颜色在CSS中设置

          /**
           * 实现思路
           * 1. 加载边界线
           * 2. 根据边界线进行平移, 创建平移面图层
           * 3. 最后加载范围高亮天地图 (让其层级高于平移面图层,将其覆盖)
           */

          // 边界线
          const boundaryLineLayer = new GeoJSONLayer({
            url: 'https://geo.datav.aliyun.com/areas_v3/bound/510100.json',
            outFields: ['*'],
            renderer: {
              type: 'simple',
              symbol: {
                type: 'simple-line',
                color: '#15C99E',
                width: 0
              }
            }
          })

          // 获取边界图形
          const { features } = await boundaryLineLayer.queryFeatures()
          const rings = features[0].geometry.rings // 拿到最大的区域坐标

          const poly = turf.polygon(rings) // 转为turf多边形

          // 向下平移
          const translatedPoly = turf.transformTranslate(poly, -5, 390)

          // 创建平移面图层
          const translationLayer = new GraphicsLayer({ title: '平移面图层' })

          const graphic = new Graphic({
            geometry: {
              type: 'polygon',
              rings: translatedPoly.geometry.coordinates[0]
            },
            symbol: {
              type: 'simple-fill',
              color: '#2E7E6C',
              // style: 'vertical', // 填充竖线
              outline: {
                width: 0,
                color: '#15C99E'
              }
            }
          })
          translationLayer.add(graphic)

          // 范围内的高亮地图
          const areaLayer = new GroupLayer({
            layers: [
              imgLayer,
              ciaLayer,
              new GeoJSONLayer({
                url: 'https://geo.datav.aliyun.com/areas_v3/bound/510100.json',
                blendMode: 'destination-in',
                outFields: ['*'],
                renderer: {
                  type: 'simple',
                  symbol: {
                    type: 'simple-fill',
                    color: [227, 139, 79, 1]
                  }
                }
              })
            ]
          })

          // map.add(translationLayer, 1)
          // map.add(areaLayer, 10)
          // map.add(boundaryLineLayer, 20)

          map.add(translationLayer) // 先添加平移面图层
          map.add(areaLayer) // 再添加范围高亮图层
          // map.add(boundaryLineLayer) // 最后添加边界线图层
        })
      })
    </script>
  </body>
</html>

注意事项

  • 天地图服务需要使用有效的 token,文中的 token 是私人的,如果地图加载不出来,请换成自己的 token。
  • 在实际开发中,要注意各个图层的添加顺序,确保范围高亮图层覆盖在平移面图层之上。
相关推荐
weixin_446260852 分钟前
Django - 让开发变得简单高效的Web框架
前端·数据库·django
蓝莓味的口香糖4 分钟前
【JS】什么是单例模式
开发语言·javascript·单例模式
ObjectX前端实验室1 小时前
【react18原理探究实践】异步可中断 & 时间分片
前端·react.js
SoaringHeart1 小时前
Flutter进阶:自定义一个 json 转 model 工具
前端·flutter·dart
努力打怪升级1 小时前
Rocky Linux 8 远程管理配置指南(宿主机 VNC + KVM 虚拟机 VNC)
前端·chrome
brzhang2 小时前
AI Agent 干不好活,不是它笨,告诉你一个残忍的现实,是你给他的工具太难用了
前端·后端·架构
brzhang2 小时前
一文说明白为什么现在 AI Agent 都把重点放在上下文工程(context engineering)上?
前端·后端·架构
reembarkation2 小时前
自定义分页控件,只显示当前页码的前后N页
开发语言·前端·javascript
gerrgwg2 小时前
React Hooks入门
前端·javascript·react.js
ObjectX前端实验室2 小时前
【react18原理探究实践】调度机制之注册任务
前端·react.js