OpenLayers总结3
一、 静态测距
1.原理
静态测距主要是针对地图上已有的矢量要素(如线要素),利用 OpenLayers 提供的几何计算函数来获取其长度。在实际操作中,先加载包含几何要素的 GeoJSON 数据到矢量图层,当鼠标指针移动到要素上时,获取该要素的几何信息,再调用 getLength
函数计算其长度。
2.代码实现步骤及注释
// 引入必要的模块
import VectorLayer from "ol/layer/Vector.js";
import VectorSource from "ol/source/Vector";
import GeoJSON from "ol/format/GeoJSON.js";
import { getLength } from "ol/sphere";
import Map from "ol/Map";
// 创建地图实例
const map = new Map({
target: "map", // 指定地图要渲染到的 HTML 元素的 ID
// 其他地图配置...
});
// 创建一个矢量图层,用于显示包含几何要素的数据
const chinaLayer = new VectorLayer({
// 配置矢量数据源
source: new VectorSource({
// 从远程 URL 加载 GeoJSON 数据
url: "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=100000",
// 指定数据的格式为 GeoJSON
format: new GeoJSON(),
}),
});
// 将矢量图层添加到地图上
map.addLayer(chinaLayer);
// 监听地图的鼠标移动事件
map.on("pointermove", (e) => {
// 获取鼠标当前位置的坐标
const coord = e.coordinate;
// 获取当前坐标处的所有要素
const features = chinaLayer.getSource().getFeaturesAtCoordinate(coord);
// 如果当前坐标处存在要素
if (features.length > 0) {
// 获取第一个要素的几何信息
const chianGeo = features[0].getGeometry();
// 使用 getLength 函数计算几何要素的长度,指定投影方式为 EPSG:4326
const length = getLength(chianGeo, {
projection: "EPSG:4326",
});
// 将长度转换为千米并保留两位小数
const lengthInKm = (length / 1000).toFixed(2);
// 输出计算得到的长度,这里可以根据需求进行其他处理,如显示在页面上
console.log(`长度: ${lengthInKm}km`);
}
});
二、 交互测距
1.原理
交互测距允许用户在地图上通过手动绘制几何图形(如线段)来实时计算其长度。借助 OpenLayers 的 Draw
交互类,用户可以在地图上绘制图形,同时监听绘制过程中的 drawstart
和 drawend
事件,在事件处理函数中获取绘制的几何信息并计算长度。
2.代码实现步骤及注释
// 引入必要的模块
import Draw from "ol/interaction/Draw";
import VectorLayer from "ol/layer/Vector.js";
import VectorSource from "ol/source/Vector";
import { getLength } from "ol/sphere";
import Map from "ol/Map";
// 创建地图实例
const map = new Map({
target: "map", // 指定地图要渲染到的 HTML 元素的 ID
// 其他地图配置...
});
// 创建一个矢量图层,用于显示用户绘制的图形
const drawLayer = new VectorLayer({
// 配置矢量数据源
source: new VectorSource(),
});
// 将绘制图层添加到地图上
map.addLayer(drawLayer);
// 初始化绘制交互对象为 null
let draw = null;
// 获取 HTML 中用于选择绘制类型的下拉框元素
const select = document.querySelector("#type-select");
// 监听下拉框的 change 事件
select.addEventListener("change", function () {
// 如果之前已经存在绘制交互,移除它
if (draw) {
map.removeInteraction(draw);
draw = null;
}
// 如果选择的是绘制线段
if (this.value === "line") {
// 创建绘制交互对象,指定绘制类型为 LineString,并将绘制结果添加到 drawLayer 的数据源中
draw = new Draw({
type: "LineString",
source: drawLayer.getSource(),
});
// 监听绘制结束事件
draw.on("drawend", (e) => {
// 获取绘制结束时的要素
const f = e.feature;
// 获取要素的几何信息
const g = f.getGeometry();
// 计算几何要素的长度,转换为千米并保留两位小数
const length = (getLength(g, { projection: "EPSG:4326" }) / 1000).toFixed(2);
// 输出线段的总长度
console.log(`线段总长度: ${length}km`);
});
// 监听绘制开始事件
draw.on("drawstart", function (e) {
// 获取正在绘制的要素
const sketch = e.feature;
// 监听要素几何信息的变化事件
sketch.getGeometry().on("change", function (e) {
// 获取变化后的几何信息
const g = e.target;
// 计算当前绘制的线段长度,转换为千米并保留两位小数
const length = (getLength(g, { projection: "EPSG:4326" }) / 1000).toFixed(2);
// 输出当前线段的长度
console.log(`当前长度: ${length}km`);
});
});
// 将绘制交互添加到地图上
map.addInteraction(draw);
}
});
三、热力图层
1.原理
热力图层用于将一组点要素以热力图的形式展示,通过不同的颜色强度来表示点的密度分布。首先需要创建点要素,然后将这些要素添加到矢量数据源中,最后使用 Heatmap
类创建热力图层并添加到地图上。
2.代码实现步骤及注释
// 引入必要的模块
import Heatmap from "ol/layer/Heatmap.js";
import VectorSource from "ol/source/Vector";
import Feature from "ol/Feature";
import { Point } from "ol/geom";
import Map from "ol/Map";
// 创建地图实例
const map = new Map({
target: "map", // 指定地图要渲染到的 HTML 元素的 ID
// 其他地图配置...
});
// 定义一组点数据,包含名称和坐标
const points = [
{ name: "黄鹤楼", coords: [114.3162, 30.5278] },
// 其他点数据...
];
// 将点数据转换为 OpenLayers 的 Feature 对象数组
const features = points.map((point) => {
return new Feature({
// 创建 Point 几何对象,指定坐标
geometry: new Point(point.coords),
// 为要素添加名称属性
name: point.name,
});
});
// 创建热力图层
const heatLayer = new Heatmap({
// 配置矢量数据源,将 Feature 数组添加到数据源中
source: new VectorSource({
features: features,
}),
});
// 将热力图层添加到地图上
map.addLayer(heatLayer);
四、要素动画
1.原理
要素动画通过不断更新要素的位置或样式来实现动态效果。可以手动计算要素的位置,也可以使用第三方库(如 ol-ext
)提供的动画类。在这个例子中,我们使用 ol_featureAnimation_Path
类创建路径动画,让一个点要素沿着指定的路径移动。
2.代码实现步骤及注释
// 引入必要的模块
import Feature from "ol/Feature";
import { LineString, Point } from "ol/geom";
import Style from "ol/style/Style";
import Stroke from "ol/style/Stroke";
import Icon from "ol/style/Icon";
import CircleStyle from "ol/style/Circle.js";
import Fill from "ol/style/Fill";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Map from "ol/Map";
import ol_featureAnimation_Path from "ol-ext/featureanimation/Path.js";
// 创建地图实例
const map = new Map({
target: "map", // 指定地图要渲染到的 HTML 元素的 ID
// 其他地图配置...
});
// 定义三个城市的坐标,用于创建路径
const cityPoints = [
[114.3055, 30.5928], // 武汉
[113.6504, 34.7638], // 郑州
[116.4074, 39.9042], // 北京
];
// 创建从武汉到郑州的连续离散点,共 200 个
const points = [];
for (let i = 0; i < 200; i++) {
const ratio = i / 200;
const point = [
cityPoints[0][0] * (1 - ratio) + cityPoints[1][0] * ratio,
cityPoints[0][1] * (1 - ratio) + cityPoints[1][1] * ratio,
];
points.push(point);
}
// 创建从郑州到北京的连续离散点,共 200 个
for (let i = 0; i < 200; i++) {
const ratio = i / 200;
const point = [
cityPoints[1][0] * (1 - ratio) + cityPoints[2][0] * ratio,
cityPoints[1][1] * (1 - ratio) + cityPoints[2][1] * ratio,
];
points.push(point);
}
// 创建表示路径的要素
const lineFeature = new Feature({
type: "route", // 要素类型为路径
// 创建 LineString 几何对象,指定路径的坐标数组
geometry: new LineString(points),
});
// 创建表示起始点的要素
const startMarker = new Feature({
type: "icon", // 要素类型为图标
// 创建 Point 几何对象,指定起始点的坐标
geometry: new Point(points[0]),
});
// 创建表示结束点的要素
const endMarker = new Feature({
type: "icon", // 要素类型为图标
// 创建 Point 几何对象,指定结束点的坐标
geometry: new Point(points[points.length - 1]),
});
// 创建表示移动点的要素
const dotMarker = new Feature({
type: "dot", // 要素类型为点
// 创建 Point 几何对象,指定移动点的初始坐标
geometry: new Point(points[0]),
});
// 定义不同类型要素的样式
const styles = {
route: new Style({
// 为路径要素设置描边样式,颜色为红色,宽度为 5
stroke: new Stroke({
color: "red",
width: 5,
}),
}),
icon: new Style({
// 为图标要素设置图标样式,指定图标的 URL 和锚点
image: new Icon({
src: "/location.png",
anchor: [0.5, 1],
}),
}),
dot: new Style({
// 为点要素设置圆形样式,半径为 5,填充颜色为绿色
image: new CircleStyle({
radius: 5,
fill: new Fill({
color: "green",
}),
}),
}),
};
// 创建矢量图层
const vectorLayer = new VectorLayer({
// 配置矢量数据源,将路径、起始点、结束点和移动点要素添加到数据源中
source: new VectorSource({
features: [lineFeature, startMarker, endMarker, dotMarker],
}),
// 根据要素的类型返回对应的样式
style: function (feature) {
return styles[feature.get("type")];
},
});
// 将矢量图层添加到地图上
map.addLayer(vectorLayer);
// 获取 HTML 中用于控制动画速度的输入框元素
const speedBtn = document.querySelector("#speed");
// 获取 HTML 中用于启动动画的按钮元素
const startBtn = document.querySelector("#start-btn");
// 初始化动画对象为 null
let anim;
// 监听启动按钮的点击事件
startBtn.addEventListener("click", startAnimation);
// 启动动画的函数
function startAnimation() {
// 更新按钮文本,表示动画正在进行
startBtn.innerHTML = "动画进行中";
// 创建路径动画对象,指定路径、速度和持续时间
anim = new ol_featureAnimation_Path({
path: lineFeature,
speed: parseFloat(speedBtn.value) * 0.0001,
duration: 2000,
});
// 在矢量图层上对移动点要素启动动画
vectorLayer.animateFeature(dotMarker, anim);
// 监听动画结束事件
anim.on("animationend", function () {
// 更新按钮文本,表示动画已结束
startBtn.innerHTML = "开始动画";
});
}