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;
}
}