<!DOCTYPE html>
<html>
<head>
<title>基于OpenLayers+rbush+turf实现高德轨迹样式</title>
<link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<script src="https://unpkg.com/rbush@2.0.1/rbush.js"></script>
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
</head>
<body>
<div id="map" class="map"></div>
<canvas id="canvas" width="5" height="10"></canvas>
<script>
var canvas = document.getElementById("canvas");
drawArrowImage(canvas,9,5);
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var map = new ol.Map({
layers: [raster],
target: 'map',
view: new ol.View({
center: [-0, 0],
zoom: 4
})
});
var source = new ol.source.Vector({wrapX: false});
var vector = new ol.layer.Vector();
map.addLayer(vector);
vector.setStyle(styleFunction);
vector.setSource(source);
function drawArrowImage(canvas,height,width){
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
if(height<2)return;
if(width<1)return;
ctx.lineWidth = 2;
ctx.strokeStyle = "#faf4ff";
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(width,height/2.0);
ctx.lineTo(0,height);
ctx.stroke();
}
function styleFunction(feature,res){
let styles = [];
styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#393bff',
width: 10
})
})
];
let trackLine= feature.getGeometry();
if(trackLine instanceof ol.geom.LineString){
//对segments建立btree索引
let tree= rbush();//路段数
trackLine.forEachSegment(function(start, end) {
var dx = end[0] - start[0];
var dy = end[1] - start[1];
//计算每个segment的方向,即箭头旋转方向
let rotation = Math.atan2(dy, dx);
let geom=new ol.geom.LineString([start,end]);
let extent=geom.getExtent();
let item = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
geom: geom,
rotation:rotation
};
tree.insert(item);
});
//轨迹地理长度
let length=trackLine.getLength();
//像素间隔步长
let stpes=40;//像素步长间隔
//将像素步长转实际地理距离步长
let geo_steps=stpes*res;
//箭头总数
let arrowsNum=parseInt(length/geo_steps);
for(let i=1;i<arrowsNum;i++){
let arraw_coor=trackLine.getCoordinateAt(i*1.0/arrowsNum);
let tol=10;//查询设置的点的容差,测试地图单位是米。如果是4326坐标系单位为度的话,改成0.0001.
let arraw_coor_buffer=[arraw_coor[0]-tol,arraw_coor[1]-tol,arraw_coor[0]+tol,arraw_coor[1]+tol];
//进行btree查询
var treeSearch = tree.search({
minX: arraw_coor_buffer[0],
minY: arraw_coor_buffer[1],
maxX: arraw_coor_buffer[2],
maxY: arraw_coor_buffer[3]
});
let arrow_rotation;
//只查询一个,那么肯定是它了,直接返回
if(treeSearch.length==1)
arrow_rotation=treeSearch[0].rotation;
else if(treeSearch.length>1){
let results=treeSearch.filter(function(item){
//换一种方案,设置一个稍小的容差,消除精度问题
let _tol=1;//消除精度误差的容差
if(item.geom.intersectsExtent([arraw_coor[0]-_tol,arraw_coor[1]-_tol,arraw_coor[0]+_tol,arraw_coor[1]+_tol]))
return true;
})
if(results.length>0)
arrow_rotation=results[0].rotation;
}
styles.push(new ol.style.Style({
geometry: new ol.geom.Point(arraw_coor),
image: new ol.style.Icon({
img: canvas,
imgSize:[canvas.width,canvas.height],
rotation: -arrow_rotation
})
}));
}
}
return styles;
}
function createLine(){
var coords = [[-1000000,1000000],[0,0],[100000,1000000]];
var mLine = new ol.geom.LineString(coords);
var mFeatrue = new ol.Feature({
geometry:mLine
})
mFeatrue.set("type","arrow");
source.addFeature(mFeatrue);
}
function clipByRect(oLine,oRect) {
let lineResult ;
if(oLine && oRect)
{
let coords = oLine.getCoordinates();
oLine = turf.lineString(coords);
lineResult = turf.bboxClip(oLine,oRect);
let temp = lineResult.geometry.coordinates;
lineResult = new ol.geom.LineString(temp);
}
return lineResult;
}
createLine();
</script>
</body>
</html>