1. 程式人生 > >OpenLayers官方示例詳解二:Drag-and-Drop Image Vector

OpenLayers官方示例詳解二:Drag-and-Drop Image Vector

目錄

四、總結

一、示例概述

    本示例實現了從資料夾中拖拉檔案到瀏覽器從而載入地理資料的功能,地理資料是以圖片的形式展示在瀏覽器。

二、程式碼詳解

2.1、建立DragAndDrop控制元件並新增到地圖

        var dragAndDropInteraction = new ol.interaction.DragAndDrop({
            formatConstructors: [                               //支援載入的地理資料的格式
                ol.format.GPX,
                ol.format.GeoJSON,
                ol.format.IGC,
                ol.format.KML,
                ol.format.TopoJSON
            ]
        });

        var map = new ol.Map({
            //新增控制元件到地圖
            interactions: ol.interaction.defaults().extend([dragAndDropInteraction]),
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                })
            ],
            target: 'map',
            view: new ol.View({
                center: [0, 0],
                zoom: 2
            })
        });

    OpenLayers提供了ol/interaction/DragAndDrop類來支援從資料夾中直接拖拉檔案資料載入到地圖上。

    formatConstructors引數用於設定支援載入的地理資料的格式。

2.2、設定資料檔案拖拉到瀏覽器後執行的操作

        dragAndDropInteraction.on('addfeatures', function(event){   //當檔案資料拖拉到瀏覽器時觸發該事件
            var vectorSource = new ol.source.Vector({        //設定資料來源
                features: event.features
            });
            map.addLayer(new ol.layer.Vector({              //初始化向量圖層並新增到地圖
                renderMode: 'image',            //向量圖層渲染為圖片
                source: vectorSource,           
                style: styleFunction            //向量圖層的樣式
            }));
            map.getView().fit(vectorSource.getExtent());    //檢視縮放至新新增的向量要素
        });

    先為DragAndDrop控制元件綁定了"addfeatures"事件的處理程式,該事件會在檔案資料拖拉到瀏覽器時觸發。

    事件的處理程式主要功能是將檔案資料裝載至向量圖層並新增到地圖中。

    可以看到,ol.layer.Vector類的style引數使用了樣式函式的形式設定向量圖層的樣式,接下來介紹該樣式函式。

2.3、樣式函式

    檢視OpenLayers的官方API可以看到ol.layer.Vector類的style引數可以接受三種類型的引數,其中一種是styleFunction(樣式函式)。

    本示例就是通過設定style引數為一個樣式函式來渲染向量圖層的樣式。

    繼續檢視styleFunction的API,可以看到styleFunction()接受兩個引數:

  • ol/Feature    ——    向量圖層的要素
  • resolution    ——    地圖解析度(螢幕上面的1畫素相對於地面的實際距離)

    瞭解了上面這些內容後,我們再來看本示例的樣式函式:

        var defaultStyle = {
            //點樣式
            'Point': new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: 'rgba(255, 255, 0, 0.5)'
                    }),
                    radius: 5,
                    stroke: new ol.style.Stroke({
                        color: '#FF0',
                        width: 1
                    })
                })
            }),
            //線樣式
            'LineString': new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: '#F00',
                    width: 3
                })
            }),
            //多變形樣式
            'Polygon': new ol.style.Style({
                fill: new ol.style.Fill({
                    color: 'rgba(0, 255, 255, 0.5)'
                }),
                stroke: new ol.style.Stroke({
                    color: '#0FF',
                    width: 1
                })
            }),
            //多點樣式
            "MultiPoint": new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: 'rgba(255, 0, 255, 0.5)'
                    }),
                    radius: 5,
                    stroke: new ol.style.Stroke({
                        color: '#F0F',
                        width: 1
                    })
                })
            }),
            //多線樣式
            'MultiLineString': new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: "#0f0",
                    width: 3
                })
            }),
            //多多邊形樣式
            'MultiPolygon': new ol.style.Style({
                fill: new ol.style.Fill({
                    color: 'rgba(0, 0, 255, 0.5)'
                }),
                stroke: new ol.style.Stroke({
                    color: '#00F',
                    width: 1
                })
            })
        };

        var styleFunction = function(feature, resolution){
            //地圖變換一次解析度,就執行一次本樣式函式
            var featureStyleFunction = feature.getStyleFunction();   //獲取要素的樣式函式
            if(featureStyleFunction){
                //如果要素擁有樣式函式
                return featureStyleFunction.call(feature, resolution);
            }else{
                return defaultStyle[feature.getGeometry().getType()];
            }
        }

    上面的程式碼,首先初始化了一個儲存多種向量圖形樣式的預設樣式物件defaultStyle,然後構建了一個樣式函式styleFunction

    styleFunction通過判斷向量圖形的型別返回defaultStyle中對應的樣式。

    需要注意的是:地圖的縮放級別的變換一次(解析度變換與縮放級別變換對應),styleFunction函式就會執行一次。

2.4、顯示新新增的要素的資訊

    接下來需要構建顯示新新增的要素的資訊的功能:當滑鼠游標放在新新增的要素上面就在地圖下面顯示該要素的資訊。

        var displayFeatureInfo = function(pixel){
            var features = [];
            map.forEachFeatureAtPixel(pixel, function(feature){
                //如果滑鼠游標所在地圖座標與要素相交,則將相交的要素新增到features陣列
                features.push(feature);
            });
            if(features.length > 0){
                //如果存在與滑鼠座標相交的要素,則將相交的要素的資訊在瀏覽器頁面中顯示出來
                var info = [];
                var i, ii;
                for(i = 0, ii = features.length; i < ii; ++i){
                    info.push(features[i].get('name'));   //將要素的'name'屬性新增到info陣列
                }
                document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
            }else{
                document.getElementById('info').innerHTML = '&nbsp;';
            }
        };

        map.on('pointermove', function(evt){            //為地圖繫結'pointermove'事件的處理程式
            if(evt.dragging){ 
                //由於地圖被滑鼠拖拽也會觸發'pointermove'事件,
                //所以這裡返回return避免地圖被拖拽時多次重複呼叫displayFeatureInfo
                //這樣做提高了效率
                return;
            }
            var pixel = map.getEventPixel(evt.originalEvent);
            displayFeatureInfo(pixel);
        });
        
        map.on('click', function(evt){                 //為地圖繫結'click'事件的事件處理程式
            displayFeatureInfo(evt.pixel);
        })

三、完整程式碼與測試

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Drag-and-Drop Image Vector</title>
    <link href="ol_v5.0.0/css/ol.css" rel="stylesheet" type="text/css" />
    <script src="ol_v5.0.0/build/ol.js" type="text/javascript"></script>
</head>
<body>
    <div id="map" class="map"></div>
    <div id="info">&nbsp;</div>

    <script>
        var defaultStyle = {
            //點樣式
            'Point': new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: 'rgba(255, 255, 0, 0.5)'
                    }),
                    radius: 5,
                    stroke: new ol.style.Stroke({
                        color: '#FF0',
                        width: 1
                    })
                })
            }),
            //線樣式
            'LineString': new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: '#F00',
                    width: 3
                })
            }),
            //多變形樣式
            'Polygon': new ol.style.Style({
                fill: new ol.style.Fill({
                    color: 'rgba(0, 255, 255, 0.5)'
                }),
                stroke: new ol.style.Stroke({
                    color: '#0FF',
                    width: 1
                })
            }),
            //多點樣式
            "MultiPoint": new ol.style.Style({
                image: new ol.style.Circle({
                    fill: new ol.style.Fill({
                        color: 'rgba(255, 0, 255, 0.5)'
                    }),
                    radius: 5,
                    stroke: new ol.style.Stroke({
                        color: '#F0F',
                        width: 1
                    })
                })
            }),
            //多線樣式
            'MultiLineString': new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: "#0f0",
                    width: 3
                })
            }),
            //多多邊形樣式
            'MultiPolygon': new ol.style.Style({
                fill: new ol.style.Fill({
                    color: 'rgba(0, 0, 255, 0.5)'
                }),
                stroke: new ol.style.Stroke({
                    color: '#00F',
                    width: 1
                })
            })
        };

        var styleFunction = function(feature, resolution){
            //地圖變換一次解析度,就執行一次本樣式函式
            var featureStyleFunction = feature.getStyleFunction();   //獲取要素的樣式函式
            if(featureStyleFunction){
                //如果要素擁有樣式函式
                return featureStyleFunction.call(feature, resolution);
            }else{
                console.log(2);
                return defaultStyle[feature.getGeometry().getType()];
            }
        }

        var dragAndDropInteraction = new ol.interaction.DragAndDrop({
            formatConstructors: [                               //支援載入的地理資料的格式
                ol.format.GPX,
                ol.format.GeoJSON,
                ol.format.IGC,
                ol.format.KML,
                ol.format.TopoJSON
            ]
        });

        var map = new ol.Map({
            //新增控制元件到地圖
            interactions: ol.interaction.defaults().extend([dragAndDropInteraction]),
            layers: [
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                })
            ],
            target: 'map',
            view: new ol.View({
                center: [0, 0],
                zoom: 2
            })
        });

        dragAndDropInteraction.on('addfeatures', function(event){   //當檔案資料拖拉到瀏覽器時觸發該事件
            var vectorSource = new ol.source.Vector({        //設定資料來源
                features: event.features
            });
            map.addLayer(new ol.layer.Vector({              //初始化向量圖層並新增到地圖
                renderMode: 'image',            //向量圖層渲染為圖片
                source: vectorSource,           
                style: styleFunction            //向量圖層的樣式
            }));
            map.getView().fit(vectorSource.getExtent());    //檢視縮放至新新增的向量要素
        });

        var displayFeatureInfo = function(pixel){
            var features = [];
            map.forEachFeatureAtPixel(pixel, function(feature){
                //如果滑鼠游標所在地圖座標與要素相交,則將相交的要素新增到features陣列
                features.push(feature);
            });
            if(features.length > 0){
                //如果存在與滑鼠座標相交的要素,則將相交的要素的資訊在瀏覽器頁面中顯示出來
                var info = [];
                var i, ii;
                for(i = 0, ii = features.length; i < ii; ++i){
                    info.push(features[i].get('name'));   //將要素的'name'屬性新增到info陣列
                }
                document.getElementById('info').innerHTML = info.join(', ') || '&nbsp';
            }else{
                document.getElementById('info').innerHTML = '&nbsp;';
            }
        };

        map.on('pointermove', function(evt){            //為地圖繫結'pointermove'事件的處理程式
            if(evt.dragging){ 
                //由於地圖被滑鼠拖拽也會觸發'pointermove'事件,
                //所以這裡返回return避免地圖被拖拽時多次重複呼叫displayFeatureInfo
                //這樣做提高了效率
                return;
            }
            var pixel = map.getEventPixel(evt.originalEvent);
            displayFeatureInfo(pixel);
        });
        
        map.on('click', function(evt){                 //為地圖繫結'click'事件的事件處理程式
            displayFeatureInfo(evt.pixel);
        })
    </script>
</body>
</html>

    隨便拖拉一個geojson檔案到瀏覽器中:

    如圖所示,檔案資料已經被成功載入到地圖中,滑鼠游標放在要素上面,頁面也能顯示相應的要素資訊。

四、總結

    實現這個功能,其實就是簡單的添加了一個DragAndDrop控制元件,得到的效果卻很不錯!