文章目录
ArcGIS API for JavaScript web端基础应用
一、环境搭建
-
获取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版本,你可以根据自己的需求选择合适的版本。
-
创建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库。
二、创建地图
- 初始化地图视图
- 在
<script>
标签内,可以使用Map
和MapView
类来创建地图。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/Map
和esri/views/MapView
模块。Map
对象通过设置basemap
属性来选择底图类型,如“streets”(街道地图)、“topographic”(地形地图)等。MapView
对象的container
属性指定地图容器的id
,map
属性关联前面创建的Map
对象,center
属性设置地图中心的经纬度,zoom
属性设置地图的缩放级别。
- 在
三、添加图层
-
添加地图服务图层
- 可以添加各种类型的图层到地图中,例如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)
将图层添加到地图中。
-
添加图形图层(用于绘制自定义图形)
- 可以创建一个图形图层来绘制点、线、多边形等图形。例如,要在地图上绘制一个红色的圆形点:
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
用于定义点的符号(颜色和大小)。先创建了图形图层并添加到地图中,然后创建了一个点、一个符号和一个图形对象,将图形对象添加到图形图层中,这样就在地图上显示了一个红色的圆形点。
四、地图交互
-
点击地图获取坐标信息
- 可以为地图视图添加事件监听器来获取用户在地图上的操作信息。例如,当用户点击地图时,获取点击位置的坐标:
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.longitude
和event.mapPoint.latitude
分别是点击位置的经度和纬度,将这些信息打印到控制台。
-
缩放和平移地图
- 用户可以通过鼠标滚轮缩放地图,也可以通过拖动地图来平移。在代码中,也可以通过编程方式实现缩放和平移。例如,要将地图缩放到指定级别:
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]; });
项目应用实例
一、城市地图应用
- 项目概述
- 构建一个城市地图应用,提供城市的基础地理信息展示,包括街道、建筑物、公园等,同时允许用户查询兴趣点(POI),如餐厅、商场、学校等。
- 功能实现
- 地图展示:
- 使用
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格式,然后通过
GraphicsLayer
和Graphic
在地图上展示。 - 例如,假设有一个包含餐厅位置(经纬度)和名称的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); }); });
- 从本地或远程的地理数据服务获取POI数据,如餐厅位置和名称等信息。可以将这些数据存储为JSON格式,然后通过
- 信息弹窗:
- 当用户点击餐厅标记时,显示一个信息弹窗,展示餐厅的详细信息,如名称、地址、电话等。可以通过为
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 }); }); });
- 当用户点击餐厅标记时,显示一个信息弹窗,展示餐厅的详细信息,如名称、地址、电话等。可以通过为
- 地图展示:
二、交通流量监测应用
- 项目概述
- 该应用主要用于展示城市交通流量状况,通过实时或近实时的数据更新,帮助交通管理部门和出行者了解交通拥堵情况。
- 功能实现
- 交通数据获取与图层创建:
- 从交通监测系统获取交通流量数据,数据格式可以是包含道路路段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); } });
- 交通数据获取与图层创建:
三、环境监测数据可视化应用
- 项目概述
- 这个应用主要用于展示环境监测数据,如空气质量、水质等信息,以地图为载体,直观地呈现环境状况的空间分布。
- 功能实现
- 环境数据图层创建:
- 从环境监测机构获取监测数据,数据可能包括监测站点的位置(经纬度)和监测指标的值(如空气质量指数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)。使用
- 数据分级可视化:
- 根据环境指标的分级标准(如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 }); }); });
- 环境数据图层创建:
特效
- 使用CSS实现简单的水波纹特效(静态地图)
- 首先,如果你只是想在一个静态地图(比如一张以地图为背景的图片)上添加水波纹特效,可以利用CSS的
radial - gradient
和@keyframes
来实现。 - HTML结构:
- 假设你有一个
div
元素作为地图容器,背景是一张地图图片。
<div class="map - with - ripple"></div>
- 假设你有一个
- CSS样式:
- 为地图容器设置背景图片和相对定位,同时创建一个伪元素
::after
来作为水波纹的载体。
- 为地图容器设置背景图片和相对定位,同时创建一个伪元素
- 首先,如果你只是想在一个静态地图(比如一张以地图为背景的图片)上添加水波纹特效,可以利用CSS的
.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秒,并且无限循环。
- 在ArcGIS地图(JavaScript API)上实现水波纹特效(动态地图)
- 当你使用ArcGIS API for JavaScript创建动态地图时,要实现水波纹特效稍微复杂一些,可能需要借助第三方库或者自定义的图形绘制。
- 思路一:使用SVG图形和JavaScript动画
- 可以在地图容器内创建一个SVG元素,在SVG元素上绘制圆形作为水波纹的基本图形,然后通过JavaScript来控制圆形的缩放和透明度变化,以实现水波纹效果。
- 添加SVG元素到地图容器:
- 首先,在HTML中确保地图容器(假设
id
为mapView
)存在,然后在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); });
- 首先,在HTML中确保地图容器(假设
- 绘制圆形并实现动画:
- 在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();
- 在SVG元素中绘制一个圆形,然后通过
- 思路二:利用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上下文中,然后通过设置合适的参数(如时间参数来控制动画),在每一帧中绘制水波纹效果。
- 创建一个WebGL上下文,在ArcGIS API for JavaScript中,可以通过
- 以下是一个非常简单的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 水波纹动效技术细节
一、环境准备
- 引入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上下文并获取相关信息
- 获取地图视图的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程序
- 加载并编译顶点着色器和片元着色器:
// 加载并编译顶点着色器
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程序的功能。
七、设置顶点数据和绘制图形
- 设置顶点数据:
我们可以在地图上指定一个点来生成水波纹特效,首先需要将该点的坐标转换为归一化设备坐标(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生成水波纹特效了。可以根据实际需求对代码进行调整和优化,比如改变水波纹的颜色、半径、波动频率等参数。
总结应用
- API版本与兼容性
- 版本选择:ArcGIS API for JavaScript等前端库会不断更新,不同版本在功能、性能和兼容性上可能有所差异。要根据项目需求选择合适的版本。如果项目对新功能需求不大,选择稳定版本可降低潜在风险;若需要最新功能,则要考虑新功能是否可能带来兼容性问题。
- 浏览器兼容性:ArcGIS前端应用需在多种浏览器中正常运行。要注意不同浏览器(如Chrome、Firefox、Safari、IE等)对WebGL、HTML5等技术的支持程度不同。例如,某些高级的地图渲染效果可能在旧版本浏览器中无法正常显示,需要进行兼容性测试和必要的代码调整。
- 安全与权限管理
- 数据安全:地图数据可能包含敏感信息,如地理坐标涉及军事设施、企业商业机密位置等。在前端传输和展示数据时,要确保数据经过适当的加密和权限控制,防止数据泄露。
- 服务访问权限:如果使用ArcGIS Server等服务,需要合理配置服务的访问权限。例如,对于只供内部使用的地图服务,要限制外部IP访问;对于需要用户认证的服务,要确保认证机制安全可靠。
- 地图加载与性能优化
- 地图数据量控制:避免加载过多不必要的地图图层或数据,因为大量数据会导致地图加载缓慢。可以根据地图的缩放级别、用户视野范围等来动态加载数据。例如,在高缩放级别显示详细的街道信息,低缩放级别只显示主要城市和交通干线。
- 缓存策略:合理利用缓存来提高地图加载速度。可以对地图瓦片、常用的地理数据等进行缓存。例如,使用浏览器本地缓存存储最近访问的地图区域,下次访问同一区域时可直接从缓存读取,减少网络请求。
- 优化代码逻辑:在编写前端代码时,避免复杂和冗余的计算。例如,避免在地图缩放、平移等频繁触发的事件中进行大量的数据处理或渲染操作,尽量将这些操作延迟或分散进行。
- 交互设计与用户体验
- 易用性:地图操作应该简单直观,如缩放、平移、查询等功能要易于用户发现和使用。可以添加清晰的操作指南或工具提示,帮助用户理解如何与地图交互。
- 响应速度:确保地图对用户操作(如点击、拖拽等)能够快速响应。例如,当用户点击地图查询某个地点信息时,要及时显示查询结果,避免让用户长时间等待。
- 可视化效果设计:合理设计地图的颜色、符号等可视化元素,以突出重要信息并确保地图易于阅读。例如,使用对比鲜明的颜色来区分不同类型的地理要素,避免颜色过于相似导致用户混淆。
- 数据准确性与更新
- 数据来源验证:确保使用的地理数据来源可靠。不准确的数据可能导致地图误导用户。可以使用官方权威机构发布的数据,如政府部门的地理信息数据。
- 数据更新机制:地理信息可能会随时间变化,如道路新建、地名变更等。要建立数据更新机制,及时更新地图数据,保证地图的时效性。可以定期从数据提供者那里获取更新后的数据集,或者通过自动化的数据更新服务来更新地图。