项目需求需要在openlayers中绘制canvas矩形,矩形顶点是openlayers中的地理坐标。
绘制的关键是解决ImageCanvas与map中canvas的相对位置关系,以及坐标点与屏幕像素的关系。
openlayers中提供了ol.source.ImageCanvas类,当地图缩放改变时,通过canvasFunction回调函数实现同步试试绘制。
最初代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加Canvas图层</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.css" />
</head>
<body>
<div id="map"></div>
<script>
//创建imageCanvasLayer图层
var imageCanvasLayer = new ol.layer.Image();
imageCanvasLayer.setSource(new ol.source.ImageCanvas({
//ImageCanvas有一个canvasFunction属性,该属性其实是一个回调函数,需要对该函数进行实现,从而创建一个canvas
canvasFunction: (extent, resolution, pixelRatio, size, projection) => {
var canvas = document.createElement('canvas');
//size是ImageCanvas的size,单位是px
canvas.width = size[0];
canvas.height = size[1];
var context = canvas.getContext('2d');
context.fillStyle = "blue";
context.fillRect(0, 0, 1000, 1000);
return canvas;
},
}));
var layers = [
new ol.layer.Tile({
source: new ol.source.OSM()//这里使用ol自带的一个地图图层作为底图
}),
imageCanvasLayer
];
var map = new ol.Map({
layers: layers,
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([78, 12]),
projection: 'EPSG:3857',
zoom: 5
})
});
</script>
</body>
</html>
运行代码,虽然绘制context.fillRect(0, 0, 1000, 1000),但发现ImageCanvas的起点在窗口外,说明ImageCanvas与map中的canvas起点不一致。
可以看出,openlayers地图中默认的map canvas原点与ImageCanvas canvas原点不一致!
通过我本人的不断尝试,通过map.getSize()
获取map canvas的长宽(单位px),与ImageCanvas canvas(canvasFunction里的size参数),获得固定比例2:3
,在canvasFunction添加以下代码,
//判断两个canvas的长宽的比例关系
var mapsize = map.getSize();
console.log('ImageCanvas size:' + size);
console.log('map size:' + size);
console.log('X_ratio:'+mapsize[0]/size[0]);
console.log('Y_ratio:'+mapsize[1]/size[1]);
在控制台可以看到:
然后可以发现两个canvas比例固定,中心点也固定(可以通过context.fillRect(size[0]/2, size[1]/2, 100, 100);
验证,图形左上角顶点始终在map canvas中间)。
泪目,终于搞清楚两个canvas究竟什么关系了!!!
重头戏来了 ,下面将openlayer的地理坐标映射到ImageCanvas中,计算两个canvas在x与y的偏移delt即可。
手画的图凑合看:
var delt = new Array(2);
delt[0] = (size[0] - mapsize[0]) / 2;
delt[1] = (size[1] - mapsize[1]) / 2;
所以:
X(ImageCanvas) = X(map canvas) + delt[0];
Y(ImageCanvas) = Y(map canvas) + delt[1];
下面实现一个右上顶点为[120.3803, 36.0704]的矩形
//先定义一个4326坐标系坐标,为青岛市坐标
var cor_4326 = [120.3803, 36.0704];
//将4326坐标系坐标转换成3857坐标系,3857坐标系就是那种坐标数值特别长的,ol默认是这种坐标,各种计算也是基于3857坐标系
var cor_3857 = ol.proj.transform(cor_4326, 'EPSG:4326', 'EPSG:3857');
//获得以map canvas为参考,获得当前坐标的像素值
var pix = map.getPixelFromCoordinate(cor_3857);
//利用delt,将坐标在map canvas中的像素位置转化为ImageCanvas的像素位置,矩形长宽随便设的
context.fillRect(pix[0] + delt[0], pix[1] + delt[1], 100, 100);
结果如下:
运行效果如图:
完整代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>添加Canvas图层</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.js"></script>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol.css" />
</head>
<body>
<div id="map"></div>
<script>
var imageCanvasLayer = new ol.layer.Image();
imageCanvasLayer.setSource(new ol.source.ImageCanvas({
canvasFunction: (extent, resolution, pixelRatio, size, projection) => {
var canvas = document.createElement('canvas');
canvas.width = size[0];
canvas.height = size[1];
var context = canvas.getContext('2d');
context.fillStyle = "blue";
var mapsize = map.getSize();
var delt = new Array(2);
delt[0] = (size[0] - mapsize[0]) / 2;
delt[1] = (size[1] - mapsize[1]) / 2;
var cor_4326 = [120.3803, 36.0704];
var cor_3857 = ol.proj.transform(cor_4326, 'EPSG:4326', 'EPSG:3857');
var pix = map.getPixelFromCoordinate(cor_3857);
console.log("pix:" + pix);
context.fillRect(pix[0] + delt[0], pix[1] + delt[1], 100, 100);
return canvas;
},
}));
var layers = [
new ol.layer.Tile({
source: new ol.source.OSM()//这里使用ol自带的一个地图图层作为底图
}),
imageCanvasLayer
];
var map = new ol.Map({
layers: layers,
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([120.3803, 36.0704]),
projection: 'EPSG:3857',
zoom: 5,
})
});
</script>
</body>
</html>
接下来是根据多个点绘制矩形,解决点与点之间的像素距离是关键,很简单,等我有空再写吧