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