OpenLayers 5 一个固定视口中心位置的球面测距demo
代码功能:使用屏幕中心点作为终点,平移地图时动态修改起始点(天津)到屏幕中心点所在位置的连线,并实时计算两点间的球面距离(EPSG:3857坐标系),显示距离的文字沿连线做出标记。
主要思想是借用了openlayers的渲染机制,监听tileLayer的postcompose事件,在回调函数中使用vectorContext的API动态绘制图形。
代码中的ol.js和ol.css请自备,版本是5.3.0
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="./include/ol.css" type="text/css" />
<script src="./include/ol.js"></script>
</head>
<style>
</style>
<body>
<div id="map" class="map"></div>
<script>
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var view = new ol.View({
center: ol.proj.fromLonLat([116.403571, 39.909193]),
zoom: 7
});
//准备一个空的矢量图层存放表示天津的点要素
var sourceVector = new ol.source.Vector()
var vector = new ol.layer.Vector({
source: sourceVector
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: view
});
//以上是常规操作
//添加天津的点要素
var tianjin = ol.proj.fromLonLat([117.247504, 39.365469]);
var tjFeature = new ol.Feature(new ol.geom.Point(tianjin));
sourceVector.addFeature(tjFeature);
//下面缓存几个样式,在postcompose的回调函数里复用,提高内存利用率
var pointStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'red'
})
})
})
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
width: 3
}),
})
var textStyle = new ol.style.Style({
text: new ol.style.Text({
//文字标签的文本内容在回调函数里动态修改
font: 'bold 15px "Open Sans", "Arial Unicode MS", "sans-serif"',
placement: 'line',
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white'
})
})
});
//监听瓦片图层的postcompose事件,在其渲染结束之后进行绘制
raster.on("postcompose", function (evt) {
//拿到vectorContex对象,开始绘制
var vCtx = evt.vectorContext;
var center = view.getCenter();
var centerFeature = new ol.Feature(new ol.geom.Point(center));
var distance = Math.floor(ol.sphere.getDistance(ol.proj.toLonLat(center), [117.247504,
39.365469
]));
var lineGeom = new ol.geom.LineString([center, tianjin]);
var lineFeature = new ol.Feature(lineGeom);
//动态修改文字样式的文本
textStyle.getText().setText("球面距离:" + distance + " 米")
//计算文字倾斜角度
textStyle.getText().setRotation(Math.atan2(center[1] - tianjin[1], -center[0] + tianjin[0]))
//绘制中心点、连线和文字标签
vCtx.drawFeature(centerFeature, pointStyle);
vCtx.drawFeature(lineFeature, lineStyle);
vCtx.drawFeature(lineFeature, textStyle);
})
</script>
</body>
</html>
把上面的例子稍作改动,可以做成一个连续打点测量路径总长度的实例:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="./include/ol.css" type="text/css" />
<script src="./include/ol.js"></script>
</head>
<style>
</style>
<body>
<input type="button" id="addInput" value="添加路径点">
<div id="map" class="map"></div>
<script>
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var view = new ol.View({
center: ol.proj.fromLonLat([116.403571, 39.909193]),
zoom: 7
});
var sourceVector = new ol.source.Vector()
var vector = new ol.layer.Vector({
source: sourceVector
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: view
});
var tianjin = ol.proj.fromLonLat([117.247504, 39.365469]);
var tjFeature = new ol.Feature(new ol.geom.Point(tianjin));
sourceVector.addFeature(tjFeature);
var pointStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'red'
})
})
})
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
width: 3
}),
})
var textStyle = new ol.style.Style({
text: new ol.style.Text({
font: 'bold 15px "Open Sans", "Arial Unicode MS", "sans-serif"',
placement: 'line',
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white'
})
})
});
var endPoint = tianjin;
var addButton = document.getElementById('addInput');
var routeLine = null;
addButton.onclick = function () {
var centerFeature = new ol.Feature(new ol.geom.Point(view.getCenter()));
if (routeLine===null) {
routeLine = new ol.Feature(new ol.geom.LineString([endPoint, view.getCenter()]));
sourceVector.addFeature(routeLine);
}else{
routeLine.getGeometry().appendCoordinate( view.getCenter());
}
sourceVector.addFeature(centerFeature);
endPoint = view.getCenter();
};
raster.on("postcompose", function (evt) {
var vCtx = evt.vectorContext;
var center = view.getCenter();
var centerFeature = new ol.Feature(new ol.geom.Point(center));
var distance = (routeLine===null?
Math.floor(ol.sphere.getDistance(ol.proj.toLonLat(center), ol.proj.toLonLat(endPoint)))
:Math.floor(ol.sphere.getLength(routeLine.getGeometry())));
var lineGeom = new ol.geom.LineString([center, endPoint]);
var lineFeature = new ol.Feature(lineGeom);
textStyle.getText().setText("球面距离:" + distance + " 米")
textStyle.getText().setRotation(Math.atan2(center[1] - endPoint[1], -center[0] + endPoint[0]))
vCtx.drawFeature(centerFeature, pointStyle);
vCtx.drawFeature(lineFeature, lineStyle);
vCtx.drawFeature(lineFeature, textStyle);
})
</script>
</body>
</html>
效果图