OpenLayers 利用ImageCanvas根据地理坐标绘制canvas图形


项目需求需要在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>

接下来是根据多个点绘制矩形,解决点与点之间的像素距离是关键,很简单,等我有空再写吧


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM