Openlayers之測量距離與面積
阿新 • • 發佈:2019-01-07
1、地圖測量功能
一般的地圖的測量功能主要表現在兩個方面,一是測量距離,一是測量面積;面積的測量是根據滑鼠繪製的範圍,通過地理座標系的轉換而計算出實際面積大小,距離的測量是根據滑鼠在地圖上繪製的點,實時計算出兩點之間的實際距離,下面我們就在Openlayers3中來實現這一功能;
2、程式碼實現
3、結果展示<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="../lib/ol/ol.js"></script> <link href="../css/ol.css" rel="stylesheet" /> <script src="../lib/jquery/jquery-1.8.2.js"></script> <link href="../css/bootstrap.min.css" rel="stylesheet" /> <script src="../lib/bootstrap/bootstrap.min.js"></script> <style type="text/css"> #map { width: 100%; height: 100%; position: absolute; } #menu { float: left; position: absolute; bottom: 10px; left: 10px; z-index: 2000; } .checkbox { left: 20px; } /** * 提示框的樣式資訊 */ .tooltip { position: relative; background: rgba(0, 0, 0, 0.5); border-radius: 4px; color: white; padding: 4px 8px; opacity: 0.7; white-space: nowrap; } .tooltip-measure { opacity: 1; font-weight: bold; } .tooltip-static { background-color: #ffffff; color: black; border: 1px solid white; } .tooltip-measure:before, .tooltip-static:before { border-top: 6px solid rgba(0, 0, 0, 0.5); border-right: 6px solid transparent; border-left: 6px solid transparent; content: ""; position: absolute; bottom: -6px; margin-left: -7px; left: 50%; } .tooltip-static:before { border-top-color: #ffffff; } #scalebar { float: left; margin-bottom: 10px; } </style> <script type="text/javascript"> $(function () { //初始化地圖 var map = new ol.Map({ target: 'map', layers: [ new ol.layer.Tile({ source:new ol.source.OSM() }) ], view: new ol.View({ center: new ol.proj.fromLonLat([114.4250, 23.0890]), zoom: 18, maxZoom: 20 }) }); //定義向量資料來源 var source = new ol.source.Vector(); //定義向量圖層 var vector = new ol.layer.Vector({ source: source, style: new ol.style.Style({ fill: new ol.style.Fill({ color:'rgba(255,255,255,0.2)' }), stroke: new ol.style.Stroke({ color: '#e21e0a', width:2 }), image: new ol.style.Circle({ radius: 5, fill: new ol.style.Fill({ color:'#ffcc33' }) }) }) }); //將向量圖層新增到地圖中 map.addLayer(vector); //新增比例尺控制元件 var scaleLineControl = new ol.control.ScaleLine({ units: 'metric', target: 'scalebar', className: 'ol-scale-line' }); map.addControl(scaleLineControl); //建立一個WGS84球體物件 var wgs84Sphere = new ol.Sphere(6378137); //建立一個當前要繪製的物件 var sketch = new ol.Feature(); //建立一個幫助提示框物件 var helpTooltipElement; //建立一個幫助提示資訊物件 var helpTooltip; //建立一個測量提示框物件 var measureTooltipElement; //建立一個測量提示資訊物件 var measureTooltip; //繼續繪製多邊形的提示資訊 var continuePolygonMsg = 'Click to continue drawing the polygon'; //繼續繪製線段的提示資訊 var continueLineMsg = 'Click to continue drawing the line'; //滑鼠移動觸發的函式 var pointerMoveHandler = function (evt) { //Indicates if the map is currently being dragged. //Only set for POINTERDRAG and POINTERMOVE events. Default is false. //如果是平移地圖則直接結束 if (evt.dragging) { return; } //幫助提示資訊 var helpMsg = 'Click to start drawing'; if (sketch) { //Get the feature's default geometry. //A feature may have any number of named geometries. //獲取繪圖物件的幾何要素 var geom = sketch.getGeometry(); //如果當前繪製的幾何要素是多邊形,則將繪製提示資訊設定為多邊形繪製提示資訊 //如果當前繪製的幾何要素是多線段,則將繪製提示資訊設定為多線段繪製提示資訊 if (geom instanceof ol.geom.Polygon) { helpMsg = continuePolygonMsg; } else if (geom instanceof ol.geom.LineString) { helpMsg = continueLineMsg; } } //設定幫助提示要素的內標籤為幫助提示資訊 helpTooltipElement.innerHTML = helpMsg; //設定幫助提示資訊的位置 //The coordinate in view projection corresponding to the original browser event. helpTooltip.setPosition(evt.coordinate); //移除幫助提示要素的隱藏樣式 $(helpTooltipElement).removeClass('hidden'); }; //觸發pointermove事件 map.on('pointermove', pointerMoveHandler); //當滑鼠移除地圖檢視的時為幫助提示要素新增隱藏樣式 $(map.getViewport()).on('mouseout', function () { $(helpTooltipElement).addClass('hidden'); }); //獲取大地測量複選框 var geodesicCheckbox = document.getElementById('geodesic'); //獲取型別 var typeSelect = document.getElementById('type'); //定義一個互動式繪圖物件 var draw; //新增互動式繪圖物件的函式 function addInteraction() { // 獲取當前選擇的繪製型別 var type = typeSelect.value == 'area' ? 'Polygon' : 'LineString'; //建立一個互動式繪圖物件 draw = new ol.interaction.Draw({ //繪製的資料來源 source: source, //繪製型別 type: type, //樣式 style: new ol.style.Style({ fill: new ol.style.Fill({ color:'rgba(255,255,255,0.2)' }), stroke: new ol.style.Stroke({ color: 'rgba(0,0,0,0.5)', lineDash: [10, 10], width:2 }), image: new ol.style.Circle({ radius: 5, stroke: new ol.style.Stroke({ color:'rgba(0,0,0,0.7)' }), fill: new ol.style.Fill({ color: 'rgba(255,255,255,0.2)' }) }) }) }); //將互動繪圖物件新增到地圖中 map.addInteraction(draw); //建立測量提示框 createMeasureTooltip(); //建立幫助提示框 createHelpTooltip(); //定義一個事件監聽 var listener; //定義一個控制滑鼠點選次數的變數 var count = 0; //繪製開始事件 draw.on('drawstart', function (evt) { //The feature being drawn. sketch = evt.feature; //提示框的座標 var tooltipCoord = evt.coordinate; //監聽幾何要素的change事件 //Increases the revision counter and dispatches a 'change' event. listener = sketch.getGeometry().on('change', function (evt) { //The event target. //獲取繪製的幾何物件 var geom = evt.target; //定義一個輸出物件,用於記錄面積和長度 var output; if (geom instanceof ol.geom.Polygon) { map.removeEventListener('singleclick'); map.removeEventListener('dblclick'); //輸出多邊形的面積 output = formatArea(geom); //Return an interior point of the polygon. //獲取多變形內部點的座標 tooltipCoord = geom.getInteriorPoint().getCoordinates(); } else if (geom instanceof ol.geom.LineString) { //輸出多線段的長度 output = formatLength(geom); //Return the last coordinate of the geometry. //獲取多線段的最後一個點的座標 tooltipCoord = geom.getLastCoordinate(); } //設定測量提示框的內標籤為最終輸出結果 measureTooltipElement.innerHTML = output; //設定測量提示資訊的位置座標 measureTooltip.setPosition(tooltipCoord); }); //地圖單擊事件 map.on('singleclick', function (evt) { //設定測量提示資訊的位置座標,用來確定滑鼠點選後測量提示框的位置 measureTooltip.setPosition(evt.coordinate); //如果是第一次點選,則設定測量提示框的文字內容為起點 if (count == 0) { measureTooltipElement.innerHTML = "起點"; } //根據滑鼠點選位置生成一個點 var point = new ol.geom.Point(evt.coordinate); //將該點要素新增到向量資料來源中 source.addFeature(new ol.Feature(point)); //更改測量提示框的樣式,使測量提示框可見 measureTooltipElement.className = 'tooltip tooltip-static'; //建立測量提示框 createMeasureTooltip(); //點選次數增加 count++; }); //地圖雙擊事件 map.on('dblclick', function (evt) { //根據 var point = new ol.geom.Point(evt.coordinate); source.addFeature(new ol.Feature(point)); }); }, this); //繪製結束事件 draw.on('drawend', function (evt) { count = 0; //設定測量提示框的樣式 measureTooltipElement.className = 'tooltip tooltip-static'; //Set the offset for this overlay. //設定偏移量 measureTooltip.setOffset([0, -7]); //清空繪製要素 sketch = null; //清空測量提示要素 measureTooltipElement = null; //建立測量提示框 createMeasureTooltip(); //Removes an event listener using the key returned by on() or once(). //移除事件監聽 ol.Observable.unByKey(listener); //移除地圖單擊事件 map.removeEventListener('singleclick'); }, this); } //建立幫助提示框 function createHelpTooltip() { //如果已經存在幫助提示框則移除 if (helpTooltipElement) { helpTooltipElement.parentNode.removeChild(helpTooltipElement); } //建立幫助提示要素的div helpTooltipElement = document.createElement('div'); //設定幫助提示要素的樣式 helpTooltipElement.className = 'tooltip hidden'; //建立一個幫助提示的覆蓋標註 helpTooltip = new ol.Overlay({ element: helpTooltipElement, offset: [15, 0], positioning:'center-left' }); //將幫助提示的覆蓋標註新增到地圖中 map.addOverlay(helpTooltip); } //建立測量提示框 function createMeasureTooltip() { //建立測量提示框的div measureTooltipElement = document.createElement('div'); measureTooltipElement.setAttribute('id','lengthLabel'); //設定測量提示要素的樣式 measureTooltipElement.className = 'tooltip tooltip-measure'; //建立一個測量提示的覆蓋標註 measureTooltip = new ol.Overlay({ element: measureTooltipElement, offset: [0, -15], positioning:'bottom-center' }); //將測量提示的覆蓋標註新增到地圖中 map.addOverlay(measureTooltip); } //測量型別發生改變時觸發事件 typeSelect.onchange = function () { //移除之前的繪製物件 map.removeInteraction(draw); //重新進行繪製 addInteraction(); }; //格式化測量長度 var formatLength = function (line) { //定義長度變數 var length; //如果大地測量複選框被勾選,則計算球面距離 if (geodesicCheckbox.checked) { //Return the coordinates of the linestring. //獲取座標串 var coordinates = line.getCoordinates(); //初始長度為0 length = 0; //獲取源資料的座標系 var sourceProj = map.getView().getProjection(); //進行點的座標轉換 for (var i = 0; i < coordinates.length - 1; i++) { //第一個點 var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326'); //第二個點 var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326'); //獲取轉換後的球面距離 //Returns the distance from c1 to c2 using the haversine formula. length += wgs84Sphere.haversineDistance(c1,c2); } } else { //Return the length of the linestring on projected plane. //計算平面距離 length = Math.round(line.getLength() * 100) / 100; } //定義輸出變數 var output; //如果長度大於1000,則使用km單位,否則使用m單位 if (length > 1000) { output = (Math.round(length / 1000 * 100) / 100) + ' ' + 'km'; //換算成KM單位 } else { output = (Math.round(length * 100) / 100) + ' ' + 'm'; //m為單位 } return output; }; //格式化測量面積 var formatArea = function (polygon) { //定義面積變數 var area; //如果大地測量複選框被勾選,則計算球面面積 if (geodesicCheckbox.checked) { //獲取初始座標系 var sourceProj = map.getView().getProjection(); //Make a complete copy of the geometry. //Transform each coordinate of the geometry from one coordinate reference system to another. //The geometry is modified in place. For example, a line will be transformed to a line and a circle to a circle. //If you do not want the geometry modified in place, first clone() it and then use this function on the clone. //克隆該幾何物件然後轉換座標系 var geom = polygon.clone().transform(sourceProj, 'EPSG:4326'); //Return the Nth linear ring of the polygon geometry. //Return null if the given index is out of range. //The exterior linear ring is available at index 0 and the interior rings at index 1 and beyond. //獲取多邊形的座標系 var coordinates = geom.getLinearRing(0).getCoordinates(); //Returns the geodesic area for a list of coordinates. //獲取球面面積 area = Math.abs(wgs84Sphere.geodesicArea(coordinates)); } else { //獲取平面面積 area = polygon.getArea(); } //定義輸出變數 var output; //當面積大於10000時,轉換為平方千米,否則為平方米 if (area > 10000) { output = (Math.round(area/1000000*100)/100) + ' ' + 'km<sup>2</sup>'; } else { output = (Math.round(area*100)/100) + ' ' + 'm<sup>2</sup>'; } return output; }; //新增互動繪圖物件 addInteraction(); }); </script> </head> <body> <div id="map"> <div id="menu"> <label>測量型別選擇</label> <select id="type"> <option value="length">長度</option> <option value="area">面積</option> </select> <label class="checkbox"><input type="checkbox" id="geodesic" />使用大地測量</label> </div> </div> <div id="scalebar"></div> </body> </html>
測量距離
測量面積
此外,還能勾選使用大地測量的複選框,進行球面距離和麵積的測量