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。
  • 在实际开发中,要注意各个图层的添加顺序,确保范围高亮图层覆盖在平移面图层之上。
相关推荐
SoaringHeart1 天前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.1 天前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu1 天前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss1 天前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师1 天前
React面试题
前端·javascript·react.js
木兮xg1 天前
react基础篇
前端·react.js·前端框架
ssshooter1 天前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘1 天前
HTML--最简的二级菜单页面
前端·html
yume_sibai1 天前
HTML HTML基础(4)
前端·html
wanzhong23331 天前
ArcGIS学习-17 实战-密度分析
学习·arcgis