L.Control.Measure = L.Control.extend({ //是否初始化 _initialized: false, //统计 _lC: 0, //测量对象集合 _measureObjs: {}, //是否完成当前测绘 _finished: true, //新测量 isNewElevation: true, moveMarker: false, //测量参数 options: { position: 'topright', autoZIndex: true, offset: [10, 10], background: "#000", color: "#fff", size: 14, closeButton: true }, initialize: function(options) { L.setOptions(this, options); return this; }, onAdd: function(map) { this._map = map; this._createControl(); switch (this.options.position) { case 'topleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'topright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginTop = this.options.offset[1] + 'px'; break; case 'bottomleft': this._container.style.marginLeft = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; case 'bottomright': this._container.style.marginRight = this.options.offset[0] + 'px'; this._container.style.marginBottom = this.options.offset[1] + 'px'; break; } return this._container; }, _createControl: function() { var _this = this; this._container = L.DomUtil.create('div', 'leaflet-bar leaflet-control-measure'); var link = L.DomUtil.create('a', 'leaflet-control-measure-link', this._container); link.title = '测量'; L.DomUtil.create('span', '', link); L.DomEvent .on(this._container, 'contextmenu', L.DomEvent.stopPropagation) .on(link, 'click', L.DomEvent.stopPropagation) .on(link, 'click', function() { if (_this._finished) { //开启新的测量 _this.start(); } else { _this._finished = true; } }) _this.start(); }, start: function() { var _this = this; _this._finished = false; L.DomUtil.addClass(_this._container, 'active'); _this._addMeasureGroup(); }, _addMeasureGroup: function() { var _this = this; if (!_this._initialized) { _this._measureGroup = new L.featureGroup(); _this._measureGroup.addTo(this._map); _this._initialized = true; } if (_this.isNewElevation) { _this._lC++; _this._measureObjs[_this._lC] = new L.FeatureGroup(); _this._measureObjs[_this._lC].addTo(_this._measureGroup); _this.isNewElevation = false; _this._measureObjs[_this._lC].measurePoints = []; } _this.tmpMarkers = []; //关闭地图双击事件 this._map.doubleClickZoom.disable(); //监听地图单击事件 this._map.on('click', _this._onClickPoint, this); //监听鼠标移动事件 this._map.on('mousemove', _this._mousemove, this); }, _mousemove: function(e) { var _this = this; e.latlng = _this.latlngRectifying(e); if (_this.moveMarker) { _this.moveMarker.setLatLng(e.latlng); if (_this._measureObjs[_this._lC].polyline) { _this._measureObjs[_this._lC].measurePoints.push([e.latlng.lat, e.latlng.lng]); var points = _this._measureObjs[_this._lC].measurePoints; if (_this._measureObjs[_this._lC].measurePoints.length == 2) { var radius = L.latLng(points[1]).distanceTo(L.latLng(points[0])); _this._measureObjs[_this._lC].circle.setRadius(radius); } else if (_this._measureObjs[_this._lC].measurePoints.length == 3 && e.latlng.indexMarker == 1) { _this._measureObjs[_this._lC].circle.setStyle({ opacity: 1 }) } else { _this._measureObjs[_this._lC].circle.setStyle({ opacity: 0 }) } if (_this._measureObjs[_this._lC].measurePoints.length > 2) { var coors = _this._clone(_this._measureObjs[_this._lC].measurePoints); coors.push(_this._measureObjs[_this._lC].measurePoints[_this._measureObjs[_this._lC].measurePoints.length - 1]); if (_this._measureObjs[_this._lC].polygon) { _this._measureObjs[_this._lC].polygon.setLatLngs([coors]); } else { _this._measureObjs[_this._lC].polygon = L.polygon([coors], { color: "#fff", weight: 0, fillColor: "#fff", fillOpacity: 0.3 }).addTo(_this._measureObjs[_this._lC]); } } _this._measureObjs[_this._lC].polyline.setLatLngs(points); //实时计算测量数据 var moveData = _this._clone(points); _this._moveInfo(moveData); _this._measureObjs[_this._lC].measurePoints.pop(); } } else { _this.moveMarker = L.circleMarker(e.latlng, { radius: 10, color: "#f00" }).addTo(_this._map) } }, _clone:function(data){ data = JSON.parse(JSON.stringify(data)); return data; }, //测量时,根据鼠标移动点位信息 _moveInfo:function(data){ var _this = this; var lineDistance = 0; for (var i = 1; i < data.length; i++) { var curcoor = data[i]; var prePoint = data[i - 1]; lineDistance = lineDistance + L.latLng(curcoor).distanceTo(prePoint); var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; if(i == data.length-1){ var pointAngle = L.Util.getAngleByLatLng(prePoint[1], prePoint[0], curcoor[1], curcoor[0]); } } //添加分段信息 var oLabelObj = L.DomUtil.create('div', 'measure-content'); var pointText = L.DomUtil.create('span', 'measure-result-text'); pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'; oLabelObj.appendChild(pointText); if(data.length > 1){ if(_this.tmpMarkers[data.length - 2]){//如果最后一个点存在,更新最后一个点信息 _this.tmpMarkers[data.length - 2].setLatLng(data[data.length - 1]); _this.tmpMarkers[data.length - 2].label.setContent(oLabelObj); }else{//如果最后一个点不存在,创建点信息 var marker = L.marker(data[data.length - 1], {icon: L.divIcon({ className: 'measuremarker', iconSize: [4, 4] }) }); marker.bindLabel(oLabelObj,{ noHide: true, clickable: true, className: 'measure-tip', offset: [0, 0] }); marker.addTo(_this._measureObjs[_this._lC]); _this.tmpMarkers.push(marker); } } }, /** * 通过坐标点计算面积 * @type {Function} * @returns {Number} 面积 * @private */ _getArea: function(_lc) { var _this = this; var latLngs = _this._measureObjs[_lc].measurePoints; var pointsCount = latLngs.length, area = 0.0, d2r = Math.PI / 180, p1, p2; if (pointsCount > 2) { for (var i = 0; i < pointsCount; i++) { p1 = latLngs[i]; p2 = latLngs[(i + 1) % pointsCount]; area += ((p2[1] - p1[1]) * d2r) * (2 + Math.sin(p1[0] * d2r) + Math.sin(p2[0] * d2r)); } area = area * 6378137.0 * 6378137.0 / 2.0; } area = Math.abs(area); if (area > 1000000) { area = (area * 0.000001).toFixed(2) + ' 平方公里'; } else { area = area.toFixed(2) + ' 米²'; } return area; }, latlngRectifying: function(e) { var _this = this; var curLatlngs = []; var curpx = e.layerPoint; var length = _this._measureObjs[_this._lC] ? _this._measureObjs[_this._lC].measurePoints.length : 0; var latlng = e.latlng; if (length > 1) { curLatlngs.push({ latlng: _this._measureObjs[_this._lC].measurePoints[0], px: _this._map.latLngToLayerPoint(_this._measureObjs[_this._lC].measurePoints[0]) }) curLatlngs.push({ latlng: _this._measureObjs[_this._lC].measurePoints[length - 1], px: _this._map.latLngToLayerPoint(_this._measureObjs[_this._lC].measurePoints[length - 1]) }) } for (var i = 0; i < curLatlngs.length; i++) { var dispx = Math.sqrt((curpx.x - curLatlngs[i].px.x) * (curpx.x - curLatlngs[i].px.x) + (curpx.y - curLatlngs[i].px.y) * (curpx.y - curLatlngs[i].px.y)); if (dispx < 10) { latlng = L.latLng(curLatlngs[i].latlng); latlng.reset = true; latlng.indexMarker = i; break; } } return latlng; }, _onClickPoint: function(e) { var _this = this; e.latlng = _this.latlngRectifying(e); if (!e.latlng.reset) { _this._measureObjs[_this._lC].measurePoints.push([e.latlng.lat, e.latlng.lng]); } else { if (e.latlng.indexMarker == 0) { _this._measureObjs[_this._lC].measurePoints.push([e.latlng.lat, e.latlng.lng]); _this._measureObjs[_this._lC].polygon.setLatLngs(_this._measureObjs[_this._lC].measurePoints); _this._measureObjs[_this._lC].polygon.setStyle({ fillColor: "#f00", color: "#f00", weight: 0, fillOpacity: 0.3 }); } else { _this._measureObjs[_this._lC].removeLayer(_this._measureObjs[_this._lC].polygon); _this._measureObjs[_this._lC].polygon = null; } _this._onFinishClick(); } if (_this._measureObjs[_this._lC].measurePoints.length == 1) { var latlngs = [ [e.latlng.lat, e.latlng.lng], [e.latlng.lat, e.latlng.lng] ]; _this._measureObjs[_this._lC].polyline = L.polyline(latlngs, { color: 'red', dashArray: 10 }).addTo(_this._measureObjs[_this._lC]); _this._measureObjs[_this._lC].circle = L.circle([e.latlng.lat, e.latlng.lng], { radius: 0, color: 'red', fillOpacity: 0 }).addTo(_this._measureObjs[_this._lC]); } else { // _this._measureObjs[_this._lC].removeLayer(_this._measureObjs[_this._lC].circle); } }, _onFinishClick: function() { _this = this; //关闭地图双击事件 this._map.doubleClickZoom.enable(); //监听地图单击事件 this._map.off('click', _this._onClickPoint, this); //监听鼠标移动事件 this._map.off('mousemove', _this._mousemove, this); _this.isNewElevation = true; _this._finished = true; _this._map.removeLayer(_this.moveMarker); _this.moveMarker = null; for(var i=0;i<_this.tmpMarkers.length;i++){ _this._measureObjs[_this._lC].removeLayer(_this.tmpMarkers[i]); } _this.tmpMarkers = []; //根据点集合渲染marker点 var coorslength = _this._measureObjs[_this._lC].measurePoints.length; _this._measureObjs[_this._lC].markerObjs = []; var lineDistance = 0; for (var i = 0; i < coorslength; i++) { var curcoor = _this._measureObjs[_this._lC].measurePoints[i]; var marker = L.marker(curcoor, { draggable: true, icon: L.divIcon({ className: 'measuremarker', iconSize: [10, 10] }) }); if (i > 0) { var prePoint = _this._measureObjs[_this._lC].measurePoints[i - 1]; lineDistance = lineDistance + L.latLng(curcoor).distanceTo(prePoint); var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; var pointAngle = L.Util.getAngleByLatLng(prePoint[1], prePoint[0], curcoor[1], curcoor[0]); //添加分段信息 var oLabelObj = L.DomUtil.create('div', 'measure-content'); var delLabel = L.DomUtil.create('div', 'measure-ico-del'); var pointText = L.DomUtil.create('span', 'measure-result-text'); pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'; delLabel.lC = _this._lC; L.DomEvent.on(delLabel, 'click', function(e) { L.DomEvent.stopPropagation(e); _this.del(delLabel.lC) }); if (i == coorslength - 1) { //测量面积 if(_this._measureObjs[_this._lC].polygon){ var area = _this._getArea(_this._lC); _this._measureObjs[_this._lC].area = area; pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'+'
'+area; } oLabelObj.appendChild(delLabel); } oLabelObj.appendChild(pointText); marker.bindLabel(oLabelObj, { noHide: true, clickable: true, className: 'measure-tip', offset: [0, 0] }) } marker.LC = _this._lC; marker.LIndex = i; marker.addTo(_this._measureObjs[_this._lC]); _this._measureObjs[_this._lC].markerObjs.push(marker); if (!(i == 0 && _this._measureObjs[_this._lC].polygon)) { marker.on("move", function(e) { _this._renderMeasure({ LC: e.target.LC, LIndex: e.target.LIndex, latlng: e.latlng }); }) } marker.on("dragend", function(e) { this._map.fire('measure-result',{ distance:_this._measureObjs[e.target.LC].distance, points:_this._measureObjs[e.target.LC].measurePoints, area:_this._measureObjs[e.target.LC].area || 0, LC:e.target.LC }); }) } _this._measureObjs[_this._lC].distance = lineDistance; this._map.fire('measure-result',{ distance:_this._measureObjs[_this._lC].distance, points:_this._measureObjs[_this._lC].measurePoints, area:_this._measureObjs[_this._lC].area || 0, LC:_this._lC }); }, _renderMeasure: function(data) { var _this = this; var latlng = [data.latlng.lat, data.latlng.lng]; _this._measureObjs[data.LC].measurePoints[data.LIndex] = latlng; var curlength = _this._measureObjs[data.LC].measurePoints.length; //如果是面,第一个点和最后一个点位置同时改变 if (_this._measureObjs[data.LC].polygon) { if (data.LIndex == 0) { _this._measureObjs[data.LC].measurePoints[curlength - 1] = latlng; _this._measureObjs[_this._lC].markerObjs[curlength - 1].setLatLng(latlng); } if (data.LIndex == curlength - 1) { _this._measureObjs[data.LC].measurePoints[0] = latlng; _this._measureObjs[_this._lC].markerObjs[0].setLatLng(latlng); } } var points = _this._measureObjs[data.LC].measurePoints; //更新circle var radius = L.latLng(points[1]).distanceTo(L.latLng(points[0])); _this._measureObjs[data.LC].circle.setRadius(radius); _this._measureObjs[data.LC].circle.setLatLng(points[0]); if (points.length == 2) { _this._measureObjs[data.LC].circle.setStyle({ opacity: 1 }) } //更新线 _this._measureObjs[data.LC].polyline.setLatLngs(points); //更新面 if (_this._measureObjs[data.LC].polygon) { _this._measureObjs[data.LC].polygon.setLatLngs([points]); } var lineDistance = 0; var coorslength = _this._measureObjs[data.LC].measurePoints.length; for (var i = 1; i < coorslength; i++) { var curcoor = _this._measureObjs[data.LC].measurePoints[i]; var prePoint = _this._measureObjs[data.LC].measurePoints[i - 1]; lineDistance = lineDistance + L.latLng(curcoor).distanceTo(prePoint); var lineDistanceStr = lineDistance > 1000 ? (lineDistance / 1000).toFixed(2) + '公里' : Math.ceil(lineDistance) + '米'; var pointAngle = L.Util.getAngleByLatLng(prePoint[1], prePoint[0], curcoor[1], curcoor[0]); //添加分段信息 var oLabelObj = L.DomUtil.create('div', 'measure-content'); var delLabel = L.DomUtil.create('div', 'measure-ico-del'); var pointText = L.DomUtil.create('span', 'measure-result-text'); pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'; delLabel.lC = _this._lC; L.DomEvent.on(delLabel, 'click', function(e) { L.DomEvent.stopPropagation(e); _this.del(delLabel.lC) }); if (i == coorslength - 1) { oLabelObj.appendChild(delLabel); //测量面积 if(_this._measureObjs[data.LC].polygon){ var area = _this._getArea(data.LC); _this._measureObjs[data.LC].area pointText.innerHTML = lineDistanceStr + '
' + pointAngle + '度'+'
'+area; } } oLabelObj.appendChild(pointText); _this._measureObjs[_this._lC].distance = lineDistance; _this._measureObjs[data.LC].markerObjs[i].label.setContent(oLabelObj); } }, /** * 删除对应lC的测距 */ del: function(lC) { var _this = this; if (_this._measureObjs[lC]) { _this._measureGroup.removeLayer(_this._measureObjs[lC]); delete _this._measureObjs[lC]; this._map.fire('measure-result',{ LC:lC, action:"del" }); } }, }); /** * 航向量算 */ L.Util.getAngleByLatLng = function(startLong,startLat,endLong,endLat){ startLong = parseFloat(startLong); startLat = parseFloat(startLat); endLong = parseFloat(endLong); endLat = parseFloat(endLat); var stsrtP = { x:startLong, y:startLat }; var endP = {}; endP.x=endLong; endP.y=endLat; var startPX_LatLongCoords = startLong; var startPY_LatLongCoords = startLat; var endPX_LatLongCoords = endLong; var endPY_LatLongCoords = endLat; var zhongjianX; var zhongjianY; zhongjianX = startPX_LatLongCoords > endPX_LatLongCoords ? startPX_LatLongCoords : endPX_LatLongCoords; zhongjianY = startPX_LatLongCoords > endPX_LatLongCoords ? startPY_LatLongCoords : endPY_LatLongCoords; var thirdX = zhongjianX; var thirdY = zhongjianY + 0.001; var prjParaPointC = {}; prjParaPointC.x=thirdX; prjParaPointC.y=thirdY; stsrtP = L.Util.transformMercator(stsrtP); endP = L.Util.transformMercator(endP); var startPX = stsrtP.x; var startPY = stsrtP.y; var endPX = endP.x; var endPY = endP.y; prjParaPointC = L.Util.transformMercator(prjParaPointC); var objChangeCx = prjParaPointC.x; var objChangeCy = prjParaPointC.y; //有三点计算角度,使用向量方法 var mx, my, ax, ay, bx, by, ma_x, ma_y, mb_x, mb_y; mx = startPX_LatLongCoords > endPX_LatLongCoords ? startPX : endPX; my = startPX_LatLongCoords > endPX_LatLongCoords ? startPY : endPY; if (mx == startPX && my == startPY) { ax = endPX; ay = endPY; } else { ax = startPX; ay = startPY; } bx = objChangeCx; by = objChangeCy; ma_x = ax - mx; ma_y = ay - my; mb_x = bx - mx; mb_y = by - my; var v1 = (ma_x * mb_x) + (ma_y * mb_y); var ma_val = Math.sqrt(ma_x * ma_x + ma_y * ma_y); var mb_val = Math.sqrt(mb_x * mb_x + mb_y * mb_y); var cosM = v1 / (ma_val * mb_val); var angleAMB = Math.acos(cosM) * 180 / Math.PI; var xiangxian = 0; // 定义象限变量 var lastAngle = 0; if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) == 0) { lastAngle = 0; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) == 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { lastAngle = 90; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) == 0) { lastAngle = 180; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) == 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { lastAngle = 270; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { xiangxian = 1; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) > 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { xiangxian = 2; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) < 0) { xiangxian = 3; } else if ((endPY_LatLongCoords - startPY_LatLongCoords) < 0 && (endPX_LatLongCoords - startPX_LatLongCoords) > 0) { xiangxian = 4; }; switch (xiangxian) { case 1: lastAngle = 180 - angleAMB; break; case 2: lastAngle = 360 - angleAMB; break; case 3: lastAngle = 360 - angleAMB; break; case 4: lastAngle = 180 - angleAMB; break; default: //alert("none"); } return parseInt(Math.round(lastAngle)); } /** * 经纬度转墨卡托 */ L.Util.transformMercator =function(lonLat){ var mercator = {}; var x = lonLat.x * 20037508.34 / 180; var y = Math.log(Math.tan((90 + lonLat.y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.x = x; mercator.y = y; return mercator; }; /** * 墨卡托转经纬度 */ L.Util.transformMercator =function(lonLat){ var mercator = {}; var x = lonLat.x * 20037508.34 / 180; var y = Math.log(Math.tan((90 + lonLat.y) * Math.PI / 360)) / (Math.PI / 180); y = y * 20037508.34 / 180; mercator.x = x; mercator.y = y; return mercator; }; /** * 测量工具 */ map2DViewer.measureToolFire = function(data) { console.log(data); }; map2DViewer.setMeasureTool = function(options,map) { var defaultData = { action: 'add', position: 'topleft', offset: [10, 10], background: "#fff", color: "#000", font_size: "14px", closeButton: true } for(key in options){ defaultData[key] = options[key]; } switch (defaultData.action) { case 'add': this.measureTool = new L.Control.Measure({ position: defaultData.position, offset: defaultData.offset, background: defaultData.background, color: defaultData.color, font_size: defaultData.font_size, closeButton: defaultData.closeButton }).addTo(map); map.on('measure-result', map2DViewer.measureToolFire); return this.distanceTool; break; case 'remove': map.off('measure-result', map2DViewer.measureToolFire); map.removeControl() break; } }