近期工作需要设计交通图,故需要设计一些类似铁路,桥梁,隧道等样式,在此记录下样式的一些效果。可能有更好的实现方式,在这里 就当抛转引玉了。
参考文章:
https://www.jianshu.com/p/e68e8e1b7474
1.铁路
需要设计以下两种样式,一种再建的,一种已完工的
样式代码:
//铁路已完工
[
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#000000",
width:6,
lineCap:"butt"
}),
zIndex:20
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#ffffff",
width:6,
lineDash:[15,15],
lineCap:"butt"
}),
zIndex:21
})
]
//铁路再建
[
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#000000",
width:6,
lineDash:[15,45],
lineCap:"butt"
}),
zIndex:20
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#ffffff",
width:6,
lineDash:[15,45],
lineDashOffset:30,
lineCap:"butt"
}),
zIndex:21
})
]
效果:
2.街道
街道大致就是白色的底加上黑色的边
样式代码
[
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#000000",
width:10,
lineCap:"butt"
}),
zIndex:20
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#ffffff",
width:6,
lineCap:"butt"
}),
zIndex:21
})
]
效果
3.隧道和桥梁
大致的想法是,利用街道的样式稍微做下调整,然后取线段的最后一个点和第一个点,加上分叉的样式,分叉点准备采用图片来弄,图个便利。
图片
样式代码
//桥梁样式
//因为绘制的时候用的是MultiLineString,如果用的是LineString,请自行调整代码
function drawsty(feature){
var myStyle = [];
myStyle.push(new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#000000",
width:10,
lineCap:"butt"
}),
zIndex:20
}));
myStyle.push(new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#FFFFFF",
width:6,
lineCap:"butt"
}),
zIndex:21
}));
var linearr = feature.getGeometry().getLineStrings();
$.each(linearr,function(i,j){
var firstcoord = j.getFirstCoordinate().join(",");
var lastcoord =j.getLastCoordinate().join(",");
//因为要给图片设置角度,所以需要遍历线的每一段,然后计算出图片需要旋转的角度
j.forEachSegment(function(start, end) {
if(firstcoord == start.join(",")){
var dx = end[0]- start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
myStyle.push(new ol.style.Style({
geometry: new ol.geom.Point(start),
image: new ol.style.Icon({
src: "image/bridge.png",
scale:0.8,
rotation: -rotation-Math.PI/2//图片旋转角度,请自行调整
})
}));
}
if(lastcoord == end.join(",")){
var dx = end[0]- start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
myStyle.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.Icon({
src: "image/bridge.png",
scale:0.8,
rotation: -rotation+Math.PI/2
})
}));
}
});
})
return myStyle;
}
//隧道样式,隧道和桥梁的不同点是,隧道的黑色边框是虚线
function drawsty(feature){
var myStyle = [];
myStyle.push(new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#000000",
width:10,
lineDash:[15,1],
lineCap:"butt"
}),
zIndex:20
}));
myStyle.push(new ol.style.Style({
stroke: new ol.style.Stroke({
color:"#FFFFFF",
width:6,
lineCap:"butt"
}),
zIndex:21
}));
var linearr = feature.getGeometry().getLineStrings();
$.each(linearr,function(i,j){
var firstcoord = j.getFirstCoordinate().join(",");
var lastcoord =j.getLastCoordinate().join(",");
j.forEachSegment(function(start, end) {
if(firstcoord == start.join(",")){
var dx = end[0]- start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
myStyle.push(new ol.style.Style({
geometry: new ol.geom.Point(start),
image: new ol.style.Icon({
src: "image/tunnel.png",
scale:0.8,
rotation: -rotation+Math.PI/2
})
}));
}
if(lastcoord == end.join(",")){
var dx = end[0]- start[0];
var dy = end[1] - start[1];
var rotation = Math.atan2(dy, dx);
myStyle.push(new ol.style.Style({
geometry: new ol.geom.Point(end),
image: new ol.style.Icon({
src: "image/tunnel.png",
scale:0.8,
rotation: -rotation-Math.PI/2
})
}));
}
});
})
return myStyle;
}
效果:
4.高德地图导航样式
采用rbush实现该功能
箭头图片
样式代码
function styleFunction(feature,res){
//轨迹线图形 此处我自己用的是MultiLineString
var trackLine= feature.getGeometry().getLineStrings()[0];
var styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#2E8B57',
width: 10
}),
zIndex:3
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000000',
width: 12
}),
zIndex:1
})
];
//对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();
var item = {
minX: extent[0],
minY: extent[1],
maxX: extent[2],
maxY: extent[3],
geom: geom,
rotation:rotation
};
tree.insert(item);
});
//轨迹地理长度
let length=trackLine.getLength();
console.log(length);
//像素间隔步长
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){
//箭头点与segment相交,返回结果。该方法实测不是很准,可能是计算中间结果
//保存到小数精度导致查询有点问题
// if(item.geom.intersectsCoordinate(arraw_coor))
// return true;
//换一种方案,设置一个稍小的容差,消除精度问题
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({
src: 'image/arrow.png',
scale:0.4,
rotation: -arrow_rotation+Math.PI/2
}),
zIndex:3
}));
}
return styles;
}
效果