当前位置: 首页 > article >正文

ArcGIS API for JavaScript 基础应用+实例展示+水波纹特效

文章目录

    • ArcGIS API for JavaScript web端基础应用
    • 项目应用实例
    • 特效
    • 利用WebGL和Shader 水波纹动效技术细节
      • 一、环境准备
      • 二、创建ArcGIS地图
      • 三、创建WebGL上下文并获取相关信息
      • 四、编写顶点着色器(Vertex Shader)代码
      • 五、编写片元着色器(Fragment Shader)代码
      • 六、在JavaScript中加载和编译Shader程序
      • 七、设置顶点数据和绘制图形
    • 总结应用

ArcGIS API for JavaScript web端基础应用

一、环境搭建

  1. 获取API

    • 首先需要在Esri官方网站(https://developers.arcgis.com/)上注册账号,然后可以获取ArcGIS API for JavaScript的相关资源。你可以通过在HTML页面中引入CDN链接来使用API,例如:
    <script src="https://js.arcgis.com/4.27/"></script>
    

    这里的“4.27”是版本号,Esri会不断更新API版本,你可以根据自己的需求选择合适的版本。

  2. 创建HTML页面结构

    • 一个基本的HTML页面用于承载地图和其他GIS组件。示例如下:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF - 8">
        <title>My First ArcGIS Map</title>
        <script src="https://js.arcgis.com/4.27/"></script>
        <style>
            #mapView {
                height: 500px;
                width: 100%;
            }
        </style>
    </head>
    <body>
        <div id="mapView"></div>
        <script>
            // 这里将添加JavaScript代码来创建地图
        </script>
    </body>
    </html>
    

    这段代码定义了一个HTML页面,其中包含一个用于放置地图的<div>元素,并通过CSS样式设置了地图容器的高度和宽度。同时,引入了ArcGIS API的JavaScript库。

二、创建地图

  1. 初始化地图视图
    • <script>标签内,可以使用MapMapView类来创建地图。Map表示地图数据本身,MapView表示地图在浏览器中的可视化视图。
    require([
        "esri/Map",
        "esri/views/MapView"
    ], function(Map, MapView) {
        const map = new Map({
            basemap: "streets"
        });
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-122.4194, 37.7749],
            zoom: 12
        });
    });
    
    • 这里使用require函数来加载esri/Mapesri/views/MapView模块。Map对象通过设置basemap属性来选择底图类型,如“streets”(街道地图)、“topographic”(地形地图)等。MapView对象的container属性指定地图容器的idmap属性关联前面创建的Map对象,center属性设置地图中心的经纬度,zoom属性设置地图的缩放级别。

三、添加图层

  1. 添加地图服务图层

    • 可以添加各种类型的图层到地图中,例如ArcGIS Server发布的地图服务图层。假设你有一个已发布的地图服务URL,如“https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer”,可以这样添加图层:
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/MapServiceLayer"
    ], function(Map, MapView, MapServiceLayer) {
        const map = new Map({
            basemap: "streets"
        });
        const layer = new MapServiceLayer("https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer");
        map.add(layer);
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-98.5795, 39.8283],
            zoom: 4
        });
    });
    
    • 这里引入了esri/layers/MapServiceLayer模块,创建了一个MapServiceLayer对象并传入地图服务的URL,然后通过map.add(layer)将图层添加到地图中。
  2. 添加图形图层(用于绘制自定义图形)

    • 可以创建一个图形图层来绘制点、线、多边形等图形。例如,要在地图上绘制一个红色的圆形点:
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/GraphicsLayer",
        "esri/Graphic",
        "esri/geometry/Point",
        "esri/symbols/SimpleMarkerSymbol"
    ], function(Map, MapView, GraphicsLayer, Graphic, Point, SimpleMarkerSymbol) {
        const map = new Map({
            basemap: "streets"
        });
        const graphicsLayer = new GraphicsLayer();
        map.add(graphicsLayer);
        const point = new Point({
            longitude: -122.4194,
            latitude: 37.7749
        });
        const symbol = new SimpleMarkerSymbol({
            color: [255, 0, 0],
            size: 10
        });
        const graphic = new Graphic({
            geometry: point,
            symbol: symbol
        });
        graphicsLayer.add(graphic);
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-122.4194, 37.7749],
            zoom: 12
        });
    });
    
    • 这个例子引入了多个模块,包括esri/layers/GraphicsLayer用于创建图形图层,esri/Graphic用于创建图形对象,esri/geometry/Point用于定义点的几何位置,esri/symbols/SimpleMarkerSymbol用于定义点的符号(颜色和大小)。先创建了图形图层并添加到地图中,然后创建了一个点、一个符号和一个图形对象,将图形对象添加到图形图层中,这样就在地图上显示了一个红色的圆形点。

四、地图交互

  1. 点击地图获取坐标信息

    • 可以为地图视图添加事件监听器来获取用户在地图上的操作信息。例如,当用户点击地图时,获取点击位置的坐标:
    require([
        "esri/Map",
        "esri/views/MapView"
    ], function(Map, MapView) {
        const map = new Map({
            basemap: "streets"
        });
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-122.4194, 37.7749],
            zoom: 12
        });
        view.on("click", function(event) {
            console.log("Clicked at:", event.mapPoint.longitude, event.mapPoint.latitude);
        });
    });
    
    • 这里通过view.on("click", function(event) {...})为地图视图添加了一个点击事件监听器。当用户点击地图时,event对象包含了点击位置的相关信息,如event.mapPoint.longitudeevent.mapPoint.latitude分别是点击位置的经度和纬度,将这些信息打印到控制台。
  2. 缩放和平移地图

    • 用户可以通过鼠标滚轮缩放地图,也可以通过拖动地图来平移。在代码中,也可以通过编程方式实现缩放和平移。例如,要将地图缩放到指定级别:
    require([
        "esri/Map",
        "esri/views/MapView"
    ], function(Map, MapView) {
        const map = new Map({
            basemap: "streets"
        });
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-122.4194, 37.7749],
            zoom: 12
        });
        // 缩放到级别15
        view.zoom = 15;
    });
    
    • 要平移地图,可以修改view.center属性。例如,将地图中心移动到新的经纬度位置:
    require([
        "esri/Map",
        "esri/views/MapView"
    ], function(Map, MapView) {
        const map = new Map({
            basemap: "streets"
        });
        const view = new MapView({
            container: "mapView",
            map: map,
            center: [-122.4194, 37.7749],
            zoom: 12
        });
        // 将地图中心移动到新位置
        view.center = [-122.5, 37.8];
    });
    

项目应用实例

一、城市地图应用

  1. 项目概述
    • 构建一个城市地图应用,提供城市的基础地理信息展示,包括街道、建筑物、公园等,同时允许用户查询兴趣点(POI),如餐厅、商场、学校等。
  2. 功能实现
    • 地图展示
      • 使用ArcGIS API for JavaScript创建地图,选择合适的底图(如“streets”底图)来展示城市的街道布局。通过MapView设置地图的初始中心位置为城市中心(例如,通过城市中心的经纬度坐标),并设置合适的缩放级别,以展示城市的主要区域。
      • 示例代码如下:
      require([
          "esri/Map",
          "esri/views/MapView"
      ], function(Map, MapView) {
          const map = new Map({
              basemap: "streets"
          });
          const view = new MapView({
              container: "mapView",
              map: map,
              center: [cityCenterLongitude, cityCenterLatitude],
              zoom: 12
          });
      });
      
    • POI查询与显示
      • 从本地或远程的地理数据服务获取POI数据,如餐厅位置和名称等信息。可以将这些数据存储为JSON格式,然后通过GraphicsLayerGraphic在地图上展示。
      • 例如,假设有一个包含餐厅位置(经纬度)和名称的JSON数据,创建图形图层并添加餐厅标记的代码如下:
      require([
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/GraphicsLayer",
          "esri/Graphic",
          "esri/geometry/Point",
          "esri/symbols/SimpleMarkerSymbol"
      ], function(Map, MapView, GraphicsLayer, Graphic, Point, SimpleMarkerSymbol) {
          const graphicsLayer = new GraphicsLayer();
          map.add(graphicsLayer);
          // 假设pois是一个包含餐厅POI数据的数组,格式为{name: "餐厅名称", longitude: 经度, latitude: 纬度}
          pois.forEach(function(poi) {
              const point = new Point({
                  longitude: poi.longitude,
                  latitude: poi.latitude
              });
              const symbol = new SimpleMarkerSymbol({
                  color: [255, 0, 0],
                  size: 10
              });
              const graphic = new Graphic({
                  geometry: point,
                  symbol: symbol,
                  attributes: {
                      name: poi.name
                  }
              });
              graphicsLayer.add(graphic);
          });
      });
      
    • 信息弹窗
      • 当用户点击餐厅标记时,显示一个信息弹窗,展示餐厅的详细信息,如名称、地址、电话等。可以通过为Graphic添加点击事件来实现。
      • 代码示例:
      graphicsLayer.forEach(function(graphic) {
          graphic.on("click", function(event) {
              const name = event.graphic.attributes.name;
              const infoWindowContent = `
                  <div>
                      <h3>${name}</h3>
                      <!-- 在这里添加更多餐厅信息,如地址、电话等 -->
                  </div>
              `;
              const infoWindow = new InfoWindow({
                  content: infoWindowContent
              });
              view.popup = infoWindow;
              view.popup.open({
                  location: event.mapPoint
              });
          });
      });
      

二、交通流量监测应用

  1. 项目概述
    • 该应用主要用于展示城市交通流量状况,通过实时或近实时的数据更新,帮助交通管理部门和出行者了解交通拥堵情况。
  2. 功能实现
    • 交通数据获取与图层创建
      • 从交通监测系统获取交通流量数据,数据格式可以是包含道路路段ID、流量速度、方向等信息的JSON或其他格式。根据道路的几何形状(如通过线要素表示道路)和流量数据,创建一个动态的交通流量图层。
      • 例如,假设交通数据包含道路的坐标数组和流量速度信息,创建交通流量图层的代码如下:
      require([
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/FeatureLayer",
          "esri/Graphic",
          "esri/geometry/Polyline",
          "esri/symbols/SimpleLineSymbol"
      ], function(Map, MapView, FeatureLayer, Graphic, Polyline, SimpleLineSymbol) {
          const trafficLayer = new FeatureLayer({
              source: [], // 初始为空,后续添加交通流量数据对应的图形
              objectIdField: "id",
              geometryType: "polyline",
              fields: [
                  {
                      name: "id",
                      alias: "ID",
                      type: "oid"
                  },
                  {
                      name: "speed",
                      alias: "Speed",
                      type: "double"
                  }
              ]
          });
          map.add(trafficLayer);
          // 假设trafficData是包含交通流量数据的数组,格式为{coordinates: [道路坐标数组], speed: 流量速度}
          trafficData.forEach(function(data) {
              const polyline = new Polyline({
                  paths: [data.coordinates]
              });
              const symbol = new SimpleLineSymbol({
                  width: 3,
                  color: getColorBasedOnSpeed(data.speed) // 根据速度返回不同颜色的函数
              });
              const graphic = new Graphic({
                  geometry: polyline,
                  symbol: symbol,
                  attributes: {
                      id: uniqueId++,
                      speed: data.speed
                  }
              });
              trafficLayer.add(graphic);
          });
      });
      
    • 数据更新机制
      • 设置定时器,每隔一定时间(如几分钟)从服务器获取最新的交通流量数据,并更新交通流量图层。在更新图层时,根据新数据修改图形的符号(如颜色、宽度)来反映交通流量的变化。
      • 示例代码:
      setInterval(function() {
          fetchTrafficData().then(function(newData) {
              trafficLayer.graphics.forEach(function(graphic, index) {
                  const newSpeed = newData[index].speed;
                  const symbol = new SimpleLineSymbol({
                      width: 3,
                      color: getColorBasedOnSpeed(newSpeed)
                  });
                  graphic.symbol = symbol;
              });
          });
      }, 5 * 60 * 1000); // 每5分钟更新一次
      
    • 交通拥堵分析与提示
      • 根据交通流量数据和预设的拥堵阈值(如速度低于一定值表示拥堵),在地图上突出显示拥堵路段,例如通过改变拥堵路段的颜色为红色,并可以添加文字提示,如“拥堵路段”。同时,还可以计算拥堵指数,为用户提供城市整体交通拥堵状况的评估。
      trafficLayer.graphics.forEach(function(graphic) {
          const speed = graphic.attributes.speed;
          if (speed < congestionThreshold) {
              const symbol = new SimpleLineSymbol({
                  width: 4,
                  color: [255, 0, 0]
              });
              graphic.symbol = symbol;
              const labelSymbol = new TextSymbol({
                  text: "拥堵路段",
                  color: [255, 255, 255],
                  xoffset: 0,
                  yoffset: -10,
                  font: {
                      size: 12,
                      family: "Arial"
                  }
              });
              const labelGraphic = new Graphic({
                  geometry: graphic.geometry.getMidpoint(),
                  symbol: labelSymbol
              });
              map.graphics.add(labelGraphic);
          }
      });
      

三、环境监测数据可视化应用

  1. 项目概述
    • 这个应用主要用于展示环境监测数据,如空气质量、水质等信息,以地图为载体,直观地呈现环境状况的空间分布。
  2. 功能实现
    • 环境数据图层创建
      • 从环境监测机构获取监测数据,数据可能包括监测站点的位置(经纬度)和监测指标的值(如空气质量指数AQI)。使用GraphicsLayer创建图形图层,根据监测数据的值设置不同的符号来表示不同的环境状况。
      • 例如,假设环境数据是一个包含监测站点位置和AQI值的数组,创建环境监测数据图层的代码如下:
      require([
          "esri/Map",
          "esri/views/MapView",
          "esri/layers/GraphicsLayer",
          "esri/Graphic",
          "esri/geometry/Point",
          "esri/symbols/SimpleMarkerSymbol"
      ], function(Map, MapView, GraphicsLayer, Graphic, Point, SimpleMarkerSymbol) {
          const envLayer = new GraphicsLayer();
          map.add(envLayer);
          // 假设envData是包含环境监测数据的数组,格式为{longitude: 经度, latitude: 纬度, aqi: AQI值}
          envData.forEach(function(data) {
              const point = new Point({
                  longitude: data.longitude,
                  latitude: data.latitude
              });
              const symbolColor = getColorByAQI(data.aqi); // 根据AQI值返回颜色的函数
              const symbol = new SimpleMarkerSymbol({
                  color: symbolColor,
                  size: 10
              });
              const graphic = new Graphic({
                  geometry: point,
                  symbol: symbol,
                  attributes: {
                      aqi: data.aqi
                  }
              });
              envLayer.add(graphic);
          });
      });
      
    • 数据分级可视化
      • 根据环境指标的分级标准(如AQI分为优、良、轻度污染、中度污染等不同级别),使用不同的颜色和符号来更清晰地展示数据。例如,对于空气质量为优的站点使用绿色标记,轻度污染的站点使用黄色标记等。
      • 函数getColorByAQI实现如下:
      function getColorByAQI(aqi) {
          if (aqi <= 50) {
              return [0, 255, 0]; // 绿色
          } else if (aqi <= 100) {
              return [255, 255, 0]; // 黄色
          } else if (aqi <= 150) {
              return [255, 165, 0]; // 橙色
          } else {
              return [255, 0, 0]; // 红色
          }
      }
      
    • 信息交互与详情展示
      • 当用户点击环境监测站点标记时,弹出信息窗口,展示详细的环境监测数据,如AQI值、监测时间、污染物成分等信息。
      envLayer.forEach(function(graphic) {
          graphic.on("click", function(event) {
              const aqi = event.graphic.attributes.aqi;
              const infoWindowContent = `
                  <div>
                      <h3>环境监测站点</h3>
                      <p>空气质量指数(AQI):${aqi}</p>
                      <!-- 在这里添加更多监测数据,如监测时间、污染物成分等 -->
                  </div>
              `;
              const infoWindow = new InfoWindow({
                  content: infoWindowContent
              });
              view.popup = infoWindow;
              view.popup.open({
                  location: event.mapPoint
              });
          });
      });
      

特效

  1. 使用CSS实现简单的水波纹特效(静态地图)
    • 首先,如果你只是想在一个静态地图(比如一张以地图为背景的图片)上添加水波纹特效,可以利用CSS的radial - gradient@keyframes来实现。
    • HTML结构
      • 假设你有一个div元素作为地图容器,背景是一张地图图片。
      <div class="map - with - ripple"></div>
      
    • CSS样式
      • 为地图容器设置背景图片和相对定位,同时创建一个伪元素::after来作为水波纹的载体。
  .map - with - ripple {
         width: 500px;
         height: 300px;
         background - image: url('your - map - image.jpg');
         background - size: cover;
         position: relative;
     }
    .map - with - ripple::after {
         content: "";
         position: absolute;
         top: 0;
         left: 0;
         width: 100%;
         height: 100%;
         background: radial - gradient(circle, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0) 100%);
         border - radius: 50%;
         animation: ripple 3s infinite;
     }
     @keyframes ripple {
         0% {
             transform: scale(0);
             opacity: 0.4;
         }
         50% {
             transform: scale(1);
             opacity: 0;
         }
         100% {
             transform: scale(2);
             opacity: 0;
         }
     }
  • 在上述代码中,radial - gradient创建了一个从中心向外渐变的白色透明效果,模拟水波纹。@keyframes ripple定义了一个动画,从初始的scale(0)(不可见)逐渐放大到scale(1)(完全显示)然后再放大到scale(2)(逐渐消失),整个过程持续3秒,并且无限循环。
  1. 在ArcGIS地图(JavaScript API)上实现水波纹特效(动态地图)
    • 当你使用ArcGIS API for JavaScript创建动态地图时,要实现水波纹特效稍微复杂一些,可能需要借助第三方库或者自定义的图形绘制。
    • 思路一:使用SVG图形和JavaScript动画
      • 可以在地图容器内创建一个SVG元素,在SVG元素上绘制圆形作为水波纹的基本图形,然后通过JavaScript来控制圆形的缩放和透明度变化,以实现水波纹效果。
      • 添加SVG元素到地图容器
        • 首先,在HTML中确保地图容器(假设idmapView)存在,然后在JavaScript中获取这个容器并添加SVG元素。
        require([
            "esri/Map",
            "esri/views/MapView"
        ], function(Map, MapView) {
            const map = new Map({
                basemap: "streets"
            });
            const view = new MapView({
                container: "mapView",
                map: map,
                center: [-122.4194, 37.7749],
                zoom: 12
            });
            const svgContainer = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svgContainer.setAttribute("width", "100%");
            svgContainer.setAttribute("height", "100%");
            document.getElementById("mapView").appendChild(svgContainer);
        });
        
      • 绘制圆形并实现动画
        • 在SVG元素中绘制一个圆形,然后通过requestAnimationFrame函数来更新圆形的属性,实现动画效果。
        const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
        circle.setAttribute("cx", "50%");
        circle.setAttribute("cy", "50%");
        circle.setAttribute("r", "0");
        circle.setAttribute("fill", "rgba(255, 255, 255, 0.4)");
        svgContainer.appendChild(circle);
        let scale = 0;
        function animateRipple() {
            requestAnimationFrame(animateRipple);
            scale += 0.01;
            if (scale > 2) {
                scale = 0;
            }
            circle.setAttribute("r", scale * 100);
            circle.setAttribute("opacity", 0.4 - scale * 0.2);
        }
        animateRipple();
        
    • 思路二:利用WebGL和Shader(更高级)
      • 如果对性能和更复杂的特效有要求,可以使用WebGL和自定义的Shader来实现水波纹特效。这需要对WebGL编程和Shader语言(如GLSL)有一定的了解。
      • 基本步骤
        • 创建一个WebGL上下文,在ArcGIS API for JavaScript中,可以通过view.context获取WebGL上下文(如果支持)。
        • 编写Vertex Shader(顶点着色器)和Fragment Shader(片元着色器)来定义水波纹的形状和颜色变化。例如,在Vertex Shader中可以根据时间和位置来改变顶点的位置,以产生波动效果;在Fragment Shader中可以控制颜色和透明度。
        • 将编写好的Shader程序加载到WebGL上下文中,然后通过设置合适的参数(如时间参数来控制动画),在每一帧中绘制水波纹效果。
      • 以下是一个非常简单的Vertex Shader示例(GLSL代码),用于产生简单的波动效果:
      attribute vec2 a_position;
      uniform float u_time;
      void main() {
          vec2 offset = vec2(0.0, sin(a_position.x * 10.0 + u_time) * 0.1);
          gl_Position = vec4(a_position + offset, 0.0, 1.0);
      }
      
      • 这是一个基础的示例,要完整实现水波纹特效还需要结合Fragment Shader来设置颜色和透明度,并且需要在JavaScript中正确地设置和更新Uniform变量(如u_time),以及处理WebGL的绘制流程,包括创建缓冲区、绑定数据等操作。这种方法比较复杂,但可以实现非常高质量和高性能的水波纹特效。

利用WebGL和Shader 水波纹动效技术细节

一、环境准备

  1. 引入ArcGIS API for JavaScript
    在HTML页面中,引入ArcGIS API for JavaScript库,确保可以正常创建和操作ArcGIS地图。示例如下:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ArcGIS Map with Water Ripple Effect</title>
    <script src="https://js.arcgis.com/4.27/"></script>
    <style>
        #mapView {
            height: 600px;
            width: 800px;
        }
    </style>
</head>
<body>
    <div id="mapView"></div>
    <script src="main.js"></script>
</body>
</html>

这里引入了版本为4.27的ArcGIS API for JavaScript库,同时设置了地图容器#mapView的样式。

二、创建ArcGIS地图

main.js文件中,首先创建一个基本的ArcGIS地图视图:

require([
    "esri/Map",
    "esri/views/MapView"
], function(Map, MapView) {
    const map = new Map({
        basemap: "streets"
    });

    const view = new MapView({
        container: "mapView",
        map: map,
        center: [-122.4194, 37.7749],
        zoom: 12
    });
});

上述代码创建了一个以streets为底图的ArcGIS地图,并设置了地图的中心位置和缩放级别。

三、创建WebGL上下文并获取相关信息

  1. 获取地图视图的WebGL上下文
    ArcGIS地图视图在支持的情况下会使用WebGL进行渲染,我们可以通过地图视图对象获取其WebGL上下文。在main.js文件中,添加以下代码:
// 获取地图视图的WebGL上下文
const gl = view.context;

if (!gl) {
    console.error("该地图视图不支持WebGL,无法生成水波纹特效");
    return;
}

这里尝试获取地图视图的WebGL上下文,如果获取失败则输出错误信息并终止后续操作。

四、编写顶点着色器(Vertex Shader)代码

顶点着色器用于处理顶点的位置等信息,以下是一个在特定点生成水波纹特效的顶点着色器代码示例:

// 顶点着色器代码
attribute vec2 a_position;
uniform float u_time;
uniform vec2 u_center; // 水波纹中心坐标(归一化设备坐标)
uniform float u_radius; // 水波纹半径

void main() {
    // 计算顶点到水波纹中心的距离
    float distanceToCenter = length(a_position - u_center);

    // 根据距离和时间计算垂直方向的偏移量,模拟水波纹的波动
    vec2 offset = vec2(0.0, sin(distanceToCenter * 10.0 + u_time) * 0.1);

    // 更新顶点位置
    gl_Position = vec4(a_position + offset, 0.0, 1.0);
}

在上述代码中:

  • attribute vec2 a_position:接收从JavaScript传递过来的顶点位置信息(这里假设是二维的)。
  • uniform float u_time:接收时间信息,用于动态改变水波纹的波动效果。
  • uniform vec2 u_center:水波纹中心坐标,这里需要以归一化设备坐标(NDC)的形式传递,取值范围通常是[-1, 1]
  • uniform float u_radius:水波纹半径,用于控制水波纹的影响范围。
  • main函数中,先计算顶点到水波纹中心的距离,然后根据距离和时间计算垂直方向的偏移量,最后更新顶点位置。

五、编写片元着色器(Fragment Shader)代码

片元着色器负责处理每个像素的颜色信息,以下是示例代码:

// 片元着色器代码
precision mediump float;
uniform vec3 u_color;

void main() {
    // 设置像素颜色
    gl_FragmentColor = vec4(u_color, 0.5);
}

这里定义了precision mediump float来设置浮点数精度,uniform vec3 u_color用于接收颜色信息,在main函数中设置像素颜色和透明度。

六、在JavaScript中加载和编译Shader程序

  1. 加载并编译顶点着色器和片元着色器
// 加载并编译顶点着色器
function loadShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    if (!gl.compileShader(shader)) {
        console.error('编译顶点着色器失败:', gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}

// 加载并编译顶点着色器和片元着色器,并创建Shader程序
function createProgram(gl, vertexShaderSource, fragmentShaderSource) {
    const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
    const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    if (!gl.linkProgram(program)) {
        console.error('链接Shader程序失败:', gl.getProgramInfoLog(program));
        return null;
    }

    return program;
}

// 顶点着色器代码字符串
const vertexShaderSource = `
// 顶点着色器代码
attribute vec2 a_position;
uniform float u_time;
uniform vec2 u_center; // 水波纹中心坐标(归一化设备坐标)
uniform float u_radius; // 水波纹半径

void main() {
    // 计算顶点到水波纹中心的方程
    float distanceToCenter = length(a_position - u_center);

    // 根据距离和时间计算垂直方向的偏移量,模拟水波纹的波动
    vec2 offset = vec2(0.0, sin(distanceToCenter * 10.0 + u_time) * 0.1);

    // 更新顶点位置
    gl_Position = vec4(a_position + offset, 0.0, 1.0);
}
`;

// 片元着色器代码字符串
const fragmentShaderSource = `
// 片元着色器代码
precision mediump float;
uniform vec3 u_color;

void main() {
    // 设置像素颜色
    gl_FragmentColor = vec4(u_color, 0.5);
}
`;

// 创建Shader程序
const program = createProgram(gl, vertexShaderSource, fragmentShaderSource);

if (!program) {
    console.error('创建Shader程序失败');
    return;
}

// 使用Shader程序
gl.useProgram(program);

上述代码实现了加载、编译顶点着色器和片元着色器,并创建和使用Shader程序的功能。

七、设置顶点数据和绘制图形

  1. 设置顶点数据
    我们可以在地图上指定一个点来生成水波纹特效,首先需要将该点的坐标转换为归一化设备坐标(NDC)。假设我们要在地图上经纬度为[-122.4194, 37.7749]的点生成水波纹特效,以下是相关代码:
// 将经纬度转换为屏幕坐标
function convertToScreenCoords(view, longitude, latitude) {
    const screenPoint = view.toScreen({
        longitude: longitude,
        latitude: latitude
    });

    // 将屏幕坐标转换为归一化设备坐标
    const ndcPoint = {
        x: (screenPoint.x / view.width) * 2 - 1,
        y: (screenPoint.y / view.height) * 2 - 1
    };

    return ndcPoint;
}

// 获取水波纹中心的归一化设备坐标
const centerNdc = convertToScreenCoords(view, -122.4194, 37.7749);

// 设置顶点数据,这里简单设置为一个正方形区域
const vertices = [
    -1.0, -1.0,
    1.0, -1.0,
    -1.0, 1.0,
    1.0, 1.0
];

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// 获取顶点着色器中的属性位置
const a_position = gl.getAttribLocation(program, 'a_position');
gl.attachVertexBuffer(a_position, buffer, 2, gl.FLOAT, false, 0);

// 设置统一变量的值
const u_time = gl.getUniformLocation(program, 'u_time');
const u_center = gl.getUniformLocation(program, 'u_center');
const u_radius = gl.getUniformLocation(program, 'u_radius');
const u_color = gl.getUniformLocation(program, 'u_color');

// 设置初始颜色
gl.uniform3f(u_color, 0.0, 0.0, 1.0);
// 设置水波纹中心坐标
gl.uniform2f(u_center, centerNdc.x, centerNdc.y);
// 设置水波纹半径
gl.uniform1f(u_radius, 0.5);

// 绘制图形
function draw() {
    // 更新时间变量
    const time = performance.now() / 1000;
    gl.uniform1f(u_time, time);

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

    requestAnimationFrame(draw);
}

draw();

在上述代码中:

  • convertToScreenCoords函数用于将经纬度转换为屏幕坐标,再进一步转换为归一化设备坐标。
  • 然后设置了顶点数据、获取了顶点着色器和片元着色器中的统一变量位置,并设置了初始颜色、水波纹中心坐标和半径等参数。
  • draw函数中,不断更新时间变量并绘制图形,以实现水波纹特效的动画效果。

通过以上步骤,就可以在ArcGIS地图中的特定点利用WebGL和Shader生成水波纹特效了。可以根据实际需求对代码进行调整和优化,比如改变水波纹的颜色、半径、波动频率等参数。

总结应用

  1. API版本与兼容性
    • 版本选择:ArcGIS API for JavaScript等前端库会不断更新,不同版本在功能、性能和兼容性上可能有所差异。要根据项目需求选择合适的版本。如果项目对新功能需求不大,选择稳定版本可降低潜在风险;若需要最新功能,则要考虑新功能是否可能带来兼容性问题。
    • 浏览器兼容性:ArcGIS前端应用需在多种浏览器中正常运行。要注意不同浏览器(如Chrome、Firefox、Safari、IE等)对WebGL、HTML5等技术的支持程度不同。例如,某些高级的地图渲染效果可能在旧版本浏览器中无法正常显示,需要进行兼容性测试和必要的代码调整。
  2. 安全与权限管理
    • 数据安全:地图数据可能包含敏感信息,如地理坐标涉及军事设施、企业商业机密位置等。在前端传输和展示数据时,要确保数据经过适当的加密和权限控制,防止数据泄露。
    • 服务访问权限:如果使用ArcGIS Server等服务,需要合理配置服务的访问权限。例如,对于只供内部使用的地图服务,要限制外部IP访问;对于需要用户认证的服务,要确保认证机制安全可靠。
  3. 地图加载与性能优化
    • 地图数据量控制:避免加载过多不必要的地图图层或数据,因为大量数据会导致地图加载缓慢。可以根据地图的缩放级别、用户视野范围等来动态加载数据。例如,在高缩放级别显示详细的街道信息,低缩放级别只显示主要城市和交通干线。
    • 缓存策略:合理利用缓存来提高地图加载速度。可以对地图瓦片、常用的地理数据等进行缓存。例如,使用浏览器本地缓存存储最近访问的地图区域,下次访问同一区域时可直接从缓存读取,减少网络请求。
    • 优化代码逻辑:在编写前端代码时,避免复杂和冗余的计算。例如,避免在地图缩放、平移等频繁触发的事件中进行大量的数据处理或渲染操作,尽量将这些操作延迟或分散进行。
  4. 交互设计与用户体验
    • 易用性:地图操作应该简单直观,如缩放、平移、查询等功能要易于用户发现和使用。可以添加清晰的操作指南或工具提示,帮助用户理解如何与地图交互。
    • 响应速度:确保地图对用户操作(如点击、拖拽等)能够快速响应。例如,当用户点击地图查询某个地点信息时,要及时显示查询结果,避免让用户长时间等待。
    • 可视化效果设计:合理设计地图的颜色、符号等可视化元素,以突出重要信息并确保地图易于阅读。例如,使用对比鲜明的颜色来区分不同类型的地理要素,避免颜色过于相似导致用户混淆。
  5. 数据准确性与更新
    • 数据来源验证:确保使用的地理数据来源可靠。不准确的数据可能导致地图误导用户。可以使用官方权威机构发布的数据,如政府部门的地理信息数据。
    • 数据更新机制:地理信息可能会随时间变化,如道路新建、地名变更等。要建立数据更新机制,及时更新地图数据,保证地图的时效性。可以定期从数据提供者那里获取更新后的数据集,或者通过自动化的数据更新服务来更新地图。

http://www.kler.cn/a/378105.html

相关文章:

  • log4j2漏洞复现(CVE-2021-44228)
  • Cherno C++学习笔记 P46 箭头运算符
  • java web springboot
  • java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
  • 【uni-app】2025最新uni-app一键登录保姆级教程(包含前后端获取手机号方法)(超强避坑指南)
  • 苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架
  • SpringBoot整合minio服务
  • windows下用CMake构建使用protobuf的应用,编译使用VS2022
  • LeetCode 3226. 使两个整数相等的位更改次数
  • UML介绍-不同类间关系
  • 【Linux】从零开始使用多路转接IO --- poll
  • 利用 Direct3D 绘制几何体—8.光栅器状态
  • 刘艳兵-DBA021-升级到Oracle Database 12c时,关于使用Export/Import方法迁移数据的说法是正确的?
  • 第三次RHCSA作业
  • 【vue】11.Vue 3生命周期钩子在实践中的具体应用
  • 《JVM第1课》Java 跨平台原理
  • qt QScrollArea详解
  • Git 的特殊配置文件
  • FPGA实现串口升级及MultiBoot(十一)QuickBoot介绍
  • ‌MySQL中‌between and的基本用法‌、范围查询
  • 干货|前端项目一些响应式布局问题(固定宽度仍可以实现响应式)
  • CTF-pwn:libc2.27指针劫持[gyctf_2020_signin]
  • 通过不当变更导致 PostgreSQL 翻车的案例分析与防范
  • WeakReference与SoftReference以及结合ReferenceQueue实践整理
  • AppInventor2能否用网络摄像头画面作为屏幕的背景?
  • Golang--函数、包、defer、系统函数、内置函数