Openlayers 教程 - 以单位米为半径,绘制圆形图形要素
- 核心代码
- 完整代码:
- 在线示例
在以往的项目维护中,出现一个问题,使用最新高清底图发现,设置地图最大等级(21级)之后,地图虽然可以渲染 21 级图层,但是并没有请求 21 级图层瓦片数据。
思考之后,认为是地图等级参数限制,经过调试发现问题所在不仅于此,后来解决问题,这里记录一下。
本文包括问题原因、问题解决核心代码以及在线示例。
核心代码
这里放上控制地图视野(View)、图层(Layer)、资源(Source)对象缩放等级的代码:
其中加载了一个显示瓦片索引的图层,用来查看图层瓦片请求情况:瓦片索引的图层
// 通过获取地图经纬度和米的转换关系,来计算经纬度半径
function createCircle1(radiusTemp){
// 通过投影获取每个经纬度单位为多少米,也就是一度多少米
const metersPerUnit = map.getView().getProjection().getMetersPerUnit();
// 创建圆形对象
const circleFeature = new ol.Feature({
geometry: new ol.geom.Circle(center, radiusTemp / metersPerUnit, 'XY'),
});
circleFeature.setStyle(getStyle());
layer.getSource().addFeature(circleFeature);
}
// 通过投影转换的方式,将米半径转为经纬度半径
function createCircle2(radiusTemp){
const circle = new ol.geom.Circle(center,
transformProjection([radiusTemp, 0], 'EPSG:3857', 'EPSG:4326')[0]
-
transformProjection([0, 0], 'EPSG:3857', 'EPSG:4326')[0],'XY');
const circleFeature = new ol.Feature({
geometry: circle,
});
circleFeature.setStyle(getStyle('#00ff00',[255, 0, 255, 0.3]));
layer.getSource().addFeature(circleFeature);
}
// 先创建米的圆,在转为经纬的圆
function createCircle3(radiusTemp){
// 创建 3857 投影下的圆形对象
const circleIn3857 = new ol.geom.Circle(
ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'), radiusTemp,'XY');
// 将圆形对象转为 4326
const circle = circleIn3857.transform('EPSG:3857','EPSG:4326');
const circleFeature = new ol.Feature({
geometry: circle,
});
circleFeature.setStyle(getStyle('#0000ff',[255, 0, 0, 0.3]));
layer.getSource().addFeature(circleFeature);
}
完整代码:
<html lang="en">
<head>
<meta charset="utf-8">
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<link rel="stylesheet" href="http://openlayers.vip/examples/css/ol.css" type="text/css">
<style>
/* 注意:这里必须给高度,否则地图初始化之后不显示;一般是计算得到高度,然后才初始化地图 */
.map {
height: 400px;
width: 100%;
float: left;
}
</style>
<!--注意:openlayers 原版的比较慢,这里引起自己服务器版-->
<script src="http://openlayers.vip/examples/resources/ol.js"></script>
<script src="./tiandituLayers.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<h2>Circle Feature</h2>
<!--地图容器,需要指定 id -->
<div id="map" class="map"></div>
<!--注意:本示例将 高德腾讯坐标设置为黑色;将百度坐标设置为黄色 -->
<!--注意:本示例将 高德腾讯坐标转为WGS84颜色设置为粉色;将百度坐标转为WS84颜色设置为绿色 -->
<script type="text/javascript">
var map = new ol.Map({
// 地图容器
target: 'map',
// 地图图层,比如底图、矢量图等
layers: [
getIMG_CLayer(),
getIBO_CLayer(),
getCIA_CLayer(),
],
// 地图视野
view: new ol.View({
projection: "EPSG:4326",
// 定位
center: [116, 39],
// 缩放
zoom: 4,
maxZoom: 18,
minZoom: 1,
})
});
// 矢量图层
var layer = initVectorLayer();
/**
* @todo 矢量图层
* @returns {VectorLayer}
* @constructor
*/
function initVectorLayer() {
//实例化一个矢量图层Vector作为绘制层
let source = new ol.source.Vector();
//创建一个图层
let customVectorLayer = new ol.layer.Vector({
source: source,
zIndex: 2,
//设置样式
style: new ol.style.Style({
//边框样式
stroke: new ol.style.Stroke({
color: 'red',
width: 5,
lineDash: [3, 5]
}),
//填充样式
fill: new ol.style.Fill({
color: 'rgba(0, 0, 255, 0.3)',
}),
image: new ol.style.Circle({
radius: 9,
fill: new ol.style.Fill({
color: 'red',
})
})
}),
});
//将绘制层添加到地图容器中
map.addLayer(customVectorLayer);
return customVectorLayer;
}
function transformProjection(arr, EPSG, EPSG2) {
try {
if (EPSG2 && EPSG) {
if (arr && arr.length === 4) {
return ol.proj.transformExtent(arr, EPSG, EPSG2);
} else {
return ol.proj.transform(arr, EPSG, EPSG2);
}
}
return undefined;
} catch (e) {
console.error(e);
}
}
function getStyle(stroke = '#ff0000',fill = [0, 0, 255, 0.3]){
return new ol.style.Style({
//边框样式
stroke: new ol.style.Stroke({
color: stroke,
width: 2,
}),
//填充样式
fill: new ol.style.Fill({
color: fill,
})
})
}
function clearLayer(){
layer && layer.getSource().clear();
}
// 半径
const radius = 10010;
const center = [121.4659, 31.2];
// 通过获取地图经纬度和米的转换关系,来计算经纬度半径
function createCircle1(radiusTemp){
clearLayer();
radiusTemp = radiusTemp || radius;
// 通过投影获取每个经纬度单位为多少米,也就是一度多少米
const metersPerUnit = map.getView().getProjection().getMetersPerUnit();
// 创建圆形对象
const circleFeature = new ol.Feature({
geometry: new ol.geom.Circle(center, radiusTemp / metersPerUnit, 'XY'),
});
circleFeature.setStyle(getStyle());
layer.getSource().addFeature(circleFeature);
// 定位
positionLayer(layer);
}
// 通过投影转换的方式,将米半径转为经纬度半径
function createCircle2(radiusTemp){
clearLayer();
radiusTemp = radiusTemp || radius;
const circle = new ol.geom.Circle(center,
transformProjection([radiusTemp, 0], 'EPSG:3857', 'EPSG:4326')[0]
-
transformProjection([0, 0], 'EPSG:3857', 'EPSG:4326')[0],'XY');
const circleFeature = new ol.Feature({
geometry: circle,
});
circleFeature.setStyle(getStyle('#00ff00',[255, 0, 255, 0.3]));
layer.getSource().addFeature(circleFeature);
// 定位
positionLayer(layer);
}
// 先创建米的圆,在转为经纬的圆
function createCircle3(radiusTemp){
clearLayer();
radiusTemp = radiusTemp || radius;
// 创建 3857 投影下的圆形对象
const circleIn3857 = new ol.geom.Circle(
ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'), radiusTemp,'XY');
// 将圆形对象转为 4326
const circle = circleIn3857.transform('EPSG:3857','EPSG:4326');
const circleFeature = new ol.Feature({
geometry: circle,
});
circleFeature.setStyle(getStyle('#0000ff',[255, 0, 0, 0.3]));
layer.getSource().addFeature(circleFeature);
// 定位
positionLayer(layer);
}
// 定位到图层 layer
function positionLayer() {
const extent = layer.getSource().getExtent();
//定位范围
map.getView().fit(extent, {
duration: 100,//动画的持续时间,
callback: function () {
// alert("positionLayer compete !")
},
});
}
</script>
<button id="createCircle1" onclick="createCircle1()">经纬度转米创建圆</button>
<button id="createCircle2" onclick="createCircle2()">投影距离转换半径创建圆</button>
<button id="createCircle3" onclick="createCircle3()">3857创建圆转经纬度</button>
</body>
</html>
在线示例
在线示例:Openlayers 以单位米为半径,绘制圆形图形要素
参考博客:
[1]: OpenLayers5在EPSG:4326下以m为单位画圆
[2]: openlayers绘制圆形的几种方式