openlayers实现箭头轨迹线
1. 实现思路
使用ol/Feature 的setStyle 方法,轨迹线可以由实线+多个箭头icon组成。setStyle可以接收一个function回调方法,根据分辨率,设定每个箭头间隔的像素,计算线要素Feature的长度,根据总长度计算箭头个数。还要计算每个箭头的位置Point,箭头的方向,将其转化成Style对象。
2. 实现过程
1.加载底图和Map对象
let gaodeMapLayer = new TileLayer({
source: new XYZ({
url: "http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
}),
});
let map = new Map({
layers: [gaodeMapLayer],
view: new View({
center: [114.31, 30.55],
projection: "EPSG:4326",
zoom: 14,
}),
target: "map",
});
2.加载矢量图层,绘制线
let layer = new VectorLayer({
source: new VectorSource(),
});
map.addLayer(layer);
3.加载测试数据到矢量图层上
let gjson = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: [
[114.2924451828003, 30.548735055676342],
[114.29841041564941, 30.543006308026428],
[114.29866790771484, 30.53731418530321],
[114.29763793945311, 30.530623666534726],
[114.29145812988281, 30.526927049704433],
[114.28613662719725, 30.528479645904042],
[114.27154541015625, 30.50666709259759],
[114.28184509277342, 30.49305949630156],
[114.30931091308594, 30.500750980290693],
[114.32304382324219, 30.51494904517773],
[114.32785034179688, 30.525004753369974],
[114.31686401367188, 30.534467998833467],
[114.30107116699219, 30.517906714408557],
[114.29557800292969, 30.513174400443376],
[114.30107116699219, 30.491876137098675],
[114.29969787597656, 30.484183951487754],
[114.29008483886717, 30.4711650216242],
[114.2749786376953, 30.47471581151385],
[114.2633056640625, 30.484183951487754],
[114.2523193359375, 30.49483450812004],
[114.24819946289062, 30.517906714408557],
[114.25506591796875, 30.538607878854556],
[114.27566528320312, 30.54688710949595],
[114.31137084960938, 30.554574334398687],
[114.33334350585938, 30.547478456100688],
[114.34364318847656, 30.53328514356082],
[114.3402099609375, 30.50903343674927],
],
},
},
],
};
let feat = geojsonFormat.readFeature(gjson.features[0], {
featureProjection: map.getView().getProjection(),
});
layer.getSource().addFeature(feat);
4.箭头样式计算
// 箭头样式
arrowLineStyles(feature, resolution) {
let styles = [];
// 线条样式
let backgroundLineStyle = new ol_style_Style({
stroke: new ol_style_Stroke({
color: "green",
width: 10,
}),
});
styles.push(backgroundLineStyle);
let geometry = feature.getGeometry();
// 获取线段长度
const length = geometry.getLength();
// 箭头间隔距离(像素)
const step = 50;
// 将间隔像素距离转换成地图的真实距离
const StepLength = step * resolution;
// 得到一共需要绘制多少个 箭头
const arrowNum = Math.floor(length / StepLength);
const rotations = [];
const distances = [0];
geometry.forEachSegment(function (start, end) {
let dx = end[0] - start[0];
let dy = end[1] - start[1];
let rotation = Math.atan2(dy, dx);
distances.unshift(Math.sqrt(dx ** 2 + dy ** 2) + distances[0]);
rotations.push(rotation);
});
// 利用之前计算得到的线段矢量信息,生成对应的点样式塞入默认样式中
// 从而绘制内部箭头
for (let i = 1; i < arrowNum; ++i) {
const arrowCoord = geometry.getCoordinateAt(i / arrowNum);
const d = i * StepLength;
const grid = distances.findIndex((x) => x <= d);
styles.push(
new ol_style_Style({
geometry: new Point(arrowCoord),
image: new ol_style_Icon({
src: routearrow,
opacity: 0.8,
anchor: [0.5, 0.5],
rotateWithView: false,
// 读取 rotations 中计算存放的方向信息
rotation: -rotations[distances.length - grid - 1],
scale: 0.8,
}),
})
);
}
return styles;
},
5.应用样式到feature上
// 设置样式
feat.setStyle(this.arrowLineStyles);
map.getView().fit(feat.getGeometry());