最近在公司的项目中,需要用到百度地图的测距和测面积功能,但是在网上只找到了测量距离的api,即BMapLib.DistanceTool。
但是测面积在网上没有找到很好的资料,百度提供的DrawingManager虽然也可以实现测面积,但是感觉太lol了,然后继续找资料,发现有人跟我遇到同样的问题,他的解决思路是对BMapLib.DistanceTool进行改造,但遗憾的是没有提供源码。
我也想过要改造BMapLib.DistanceTool,但是这个对我来说很有挑战性,毕竟js我差不多是小白,今天闲来无事,决定一试。下载了BMapLib.DistanceTool的源码看,大部分都看不懂,呵呵,不过我要做的工作就是在事件处理中加入自己的逻辑,寻着这个思路,经过几番折腾,终于搞定了,整体效果自己还比较满意。
好了,废话不多说,接下来进入重点,我把百度地图实现测量面积源码公布下(Java成长交流学习群:184998348),代码下载地址:https://download.csdn.net/download/hgq0916/12403463。分享给大家,若有大神路过,别见怪,哈哈。
首先来张效果图:
下面是源码:
1.measureAreaTool_baidu.html
<!DOCTYPE html>
<html>
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> <style type="text/css"> body, html{width: 100%;height: 100%;margin:0;font-family:"微软雅黑";} #allmap {width: 100%; height:500px; overflow: hidden;} #result {width:100%;font-size:12px;} </style><script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你的AK"></script> <script src="js/GeoUtils.js" type="text/javascript"></script><script type="text/javascript" src="js/AreaTool_min.js"></script><title>百度地图API功能演示</title>
</head>
<body><div id="allmap" style="overflow:hidden;zoom:1;position:relative;"> <div id="map" style="height:100%;-webkit-transition: all 0.5s ease-in-out;transition: all 0.5s ease-in-out;"> </div> </div><div id="result"> <input type="button" value="面积测量" onclick="measureArea(this)" /><br/></div><script type="text/javascript"> var map = new BMap.Map('map');var poi = new BMap.Point(113.948913,22.530844); map.centerAndZoom(poi, 16); map.enableScrollWheelZoom();//添加测量面积工具var measureAreaTool = createMeasureAreaTool(map);//面积测量var measureArea = function(e){measureAreaTool.open();}
</script>
</body>
</html>
2.依赖的js
2.1 百度地图的核心js文件,这个用于显示百度地图的,不多说
2.2 AreaTool_min.js 这个就是我改造百度地图测距js后自己创建的测面积工具,完成对面积的测量
// 百度地图API功能
var BMapLib = window.BMapLib = BMapLib || {}; (function() {var c = c || {guid: "$BAIDU$"}; (function() {window[c.guid] = {};c.extend = function(g, e) {for (var f in e) {if (e.hasOwnProperty(f)) {g[f] = e[f]}}return g};c.lang = c.lang || {};c.lang.guid = function() {return "TANGRAM__" + (window[c.guid]._counter++).toString(36)};window[c.guid]._counter = window[c.guid]._counter || 1;window[c.guid]._instances = window[c.guid]._instances || {};c.lang.Class = function(e) {this.guid = e || c.lang.guid();window[c.guid]._instances[this.guid] = this};window[c.guid]._instances = window[c.guid]._instances || {};c.lang.isString = function(e) {return "[object String]" == Object.prototype.toString.call(e)};c.lang.isFunction = function(e) {return "[object Function]" == Object.prototype.toString.call(e)};c.lang.Class.prototype.toString = function() {return "[object " + (this._className || "Object") + "]"};c.lang.Class.prototype.dispose = function() {delete window[c.guid]._instances[this.guid];for (var e in this) {if (!c.lang.isFunction(this[e])) {delete this[e]}}this.disposed = true};c.lang.Event = function(e, f) {this.type = e;this.returnValue = true;this.target = f || null;this.currentTarget = null};c.lang.Class.prototype.addEventListener = function(h, g, f) {if (!c.lang.isFunction(g)) {return} ! this.__listeners && (this.__listeners = {});var e = this.__listeners,i;if (typeof f == "string" && f) {if (/[^\w\-]/.test(f)) {throw ("nonstandard key:" + f)} else {g.hashCode = f;i = f}}h.indexOf("on") != 0 && (h = "on" + h);typeof e[h] != "object" && (e[h] = {});i = i || c.lang.guid();g.hashCode = i;e[h][i] = g};c.lang.Class.prototype.removeEventListener = function(g, f) {if (c.lang.isFunction(f)) {f = f.hashCode} else {if (!c.lang.isString(f)) {return}} ! this.__listeners && (this.__listeners = {});g.indexOf("on") != 0 && (g = "on" + g);var e = this.__listeners;if (!e[g]) {return}e[g][f] && delete e[g][f]};c.lang.Class.prototype.dispatchEvent = function(h, e) {if (c.lang.isString(h)) {h = new c.lang.Event(h)} ! this.__listeners && (this.__listeners = {});e = e || {};for (var g in e) {h[g] = e[g]}var g, f = this.__listeners,j = h.type;h.target = h.target || this;h.currentTarget = this;j.indexOf("on") != 0 && (j = "on" + j);c.lang.isFunction(this[j]) && this[j].apply(this, arguments);if (typeof f[j] == "object") {for (g in f[j]) {f[j][g].apply(this, arguments)}}return h.returnValue};c.lang.inherits = function(k, i, h) {var g, j, e = k.prototype,f = new Function();f.prototype = i.prototype;j = k.prototype = new f();for (g in e) {j[g] = e[g]}k.prototype.constructor = k;k.superClass = i.prototype;if ("string" == typeof h) {j._className = h}};c.dom = c.dom || {};c._g = c.dom._g = function(e) {if (c.lang.isString(e)) {return document.getElementById(e)}return e};c.g = c.dom.g = function(e) {if ("string" == typeof e || e instanceof String) {return document.getElementById(e)} else {if (e && e.nodeName && (e.nodeType == 1 || e.nodeType == 9)) {return e}}return null};c.insertHTML = c.dom.insertHTML = function(h, e, g) {h = c.dom.g(h);var f, i;if (h.insertAdjacentHTML) {h.insertAdjacentHTML(e, g)} else {f = h.ownerDocument.createRange();e = e.toUpperCase();if (e == "AFTERBEGIN" || e == "BEFOREEND") {f.selectNodeContents(h);f.collapse(e == "AFTERBEGIN")} else {i = e == "BEFOREBEGIN";f[i ? "setStartBefore": "setEndAfter"](h);f.collapse(i)}f.insertNode(f.createContextualFragment(g))}return h};c.ac = c.dom.addClass = function(k, m) {k = c.dom.g(k);var f = m.split(/\s+/),e = k.className,j = " " + e + " ",h = 0,g = f.length;for (; h < g; h++) {if (j.indexOf(" " + f[h] + " ") < 0) {e += (e ? " ": "") + f[h]}}k.className = e;return k};c.event = c.event || {};c.event._listeners = c.event._listeners || [];c.on = c.event.on = function(f, i, k) {i = i.replace(/^on/i, "");f = c._g(f);var j = function(m) {k.call(f, m)},e = c.event._listeners,h = c.event._eventFilter,l,g = i;i = i.toLowerCase();if (h && h[i]) {l = h[i](f, i, j);g = l.type;j = l.listener}if (f.addEventListener) {f.addEventListener(g, j, false)} else {if (f.attachEvent) {f.attachEvent("on" + g, j)}}e[e.length] = [f, i, k, j, g];return f};c.un = c.event.un = function(g, j, f) {g = c._g(g);j = j.replace(/^on/i, "").toLowerCase();var m = c.event._listeners,h = m.length,i = !f,l, k, e;while (h--) {l = m[h];if (l[1] === j && l[0] === g && (i || l[2] === f)) {k = l[4];e = l[3];if (g.removeEventListener) {g.removeEventListener(k, e, false)} else {if (g.detachEvent) {g.detachEvent("on" + k, e)}}m.splice(h, 1)}}return g};c.preventDefault = c.event.preventDefault = function(e) {if (e.preventDefault) {e.preventDefault()} else {e.returnValue = false}}})();//TODOvar d = BMapLib.MeasureAreaTool = function(f, e) {if (!f) {return}this._map = f;e = e || {};this._opts = c.extend(c.extend(this._opts || {},{tips: "\u6d4b\u8ddd",followText: "\u5355\u51fb\u786e\u5b9a\u5730\u70b9\uff0c\u53cc\u51fb\u7ed3\u675f",unit: "metric",lineColor: "#ff6319",lineStroke: 2,opacity: 0.8,lineStyle: "solid",cursor: "http://api.map.baidu.com/images/ruler.cur",secIcon: null,closeIcon: null}), e);this._followTitle = null;this._points = [];this._paths = [];this._dots = [];this._segDistance = [];this._overlays = [];this._enableMassClear = true,this._units = {metric: {name: "metric",conv: 1,incon: 1000,u1: "\u7c73",u2: "\u516c\u91cc"},us: {name: "us",conv: 3.2808,incon: 5279.856,u1: "\u82f1\u5c3a",u2: "\u82f1\u91cc"}};this._isOpen = false;this._startFollowText = "\u5355\u51fb\u786e\u5b9a\u8d77\u70b9";this._movingTimerId = null;this._styles = {BMapLib_diso: "height:17px;width:5px;position:absolute;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat left top",BMapLib_disi: "color:#7a7a7a;position:absolute;left:5px;padding:0 4px 1px 0;line-height:17px;background:url(http://api.map.baidu.com/images/dis_box_01.gif) no-repeat right top",BMapLib_disBoxDis: "color:#ff6319;font-weight:bold"};if (this._opts.lineStroke <= 0) {this._opts.lineStroke = 2}if (this._opts.opacity > 1) {this._opts.opacity = 1} else {if (this._opts.opacity < 0) {this._opts.opacity = 0}}if (this._opts.lineStyle != "solid" && this._opts.lineStyle != "dashed") {this._opts.lineStyle = "solid"}if (!this._units[this._opts.unit]) {this._opts.unit = "metric"}this.text = "\u6d4b\u8ddd"};c.lang.inherits(d, c.lang.Class, "DistanceTool");d.prototype._bind = function() {this._setCursor(this._opts.cursor);var f = this;c.on(this._map.getContainer(), "mousemove",function(i) {if (!f._isOpen) {return}if (!f._followTitle) {return}i = window.event || i;var g = i.target || i.srcElement;if (g != a.getDom(f._map)) {f._followTitle.hide();return}if (!f._mapMoving) {f._followTitle.show()}var h = a.getDrawPoint(i, true);f._followTitle.setPosition(h)});if (this._startFollowText) {var e = this._followTitle = new BMap.Label(this._startFollowText, {offset: new BMap.Size(14, 16)});this._followTitle.setStyles({color: "#333",borderColor: "#ff0103"})}};d.prototype.open = function() {if (this._isOpen == true) {return true}if ( !! BMapLib._toolInUse) {return}this._isOpen = true;BMapLib._toolInUse = true;if (this._mapMoving) {delete this._mapMoving}var h = this;if (!this._binded) {this._binded = true;this._bind();this._map.addEventListener("moving",function() {h._hideCurrent()})}if (this._followTitle) {this._map.addOverlay(this._followTitle);this._followTitle.hide()}var g = function(q) {//TODOvar l = h._map;//获取map对象if (!h._isOpen) {//判断测距工具是否打开,关闭则返回return}q = window.event || q;var n = a.getDrawPoint(q, true);//获取鼠标点击的点if (!h._isPointValid(n)) {//判断点是否有效return}h._bind.initX = q.pageX || q.clientX || 0;//绑定当前的坐标h._bind.initY = q.pageY || q.clientY || 0;if (h._points.length > 0) {var t = l.pointToPixel(h._points[h._points.length - 1]);//获取点数组最后一个元素,转换为Pixel点var m = l.pointToPixel(n);//将当前的点转换为Pixel点var p = Math.sqrt(Math.pow(t.x - m.x, 2) + Math.pow(t.y - m.y, 2));//求两个点的距离if (p < 5) {//距离小于5则返回return}}h._bind.x = q.layerX || q.offsetX || 0;//保存当前坐标h._bind.y = q.layerY || q.offsetY || 0;h._points.push(n);//将当前坐标存入数组h._addSecPoint(n);//TODOif (h._paths.length == 0) {h._formatTitle(1, h._opts.followText, h._getTotalDistance())}if (h._paths.length > 0) {h._paths[h._paths.length - 1].show();h._paths[h._paths.length - 1].setStrokeOpacity(h._opts.opacity)}var w = new BMap.Polyline([n, n], {enableMassClear: h._enableMassClear});h._map.addOverlay(w);h._paths.push(w);h._overlays.push(w);w.setStrokeWeight(h._opts.lineStroke);w.setStrokeColor(h._opts.lineColor);w.setStrokeOpacity(h._opts.opacity / 2);w.setStrokeStyle(h._opts.lineStyle);if (h._mapMoving) {w.hide()}if (h._points.length > 1) {var o = h._paths[h._points.length - 2];o.setPositionAt(1, n)}var r = "";var v;if (h._points.length > 1) {var u = h._setSegDistance(h._points[h._points.length - 2], h._points[h._points.length - 1]);var s = h._getTotalDistance();r = h._formatDisStr(s);v = new BMap.Label(r, {offset: new BMap.Size(10, -5),enableMassClear: h._enableMassClear});} else {r = "\u8d77\u70b9";v = new BMap.Label(r, {offset: new BMap.Size(-10, -25),enableMassClear: h._enableMassClear});}// var v = new BMap.Label(r, {// offset: new BMap.Size(10, -5),// enableMassClear: h._enableMassClear// });v.setStyles({color: "#333",borderColor: "#ff0103"});h._map.addOverlay(v);h._formatSegLabel(v, r);h._overlays.push(v);n.disLabel = v;v.setPosition(n);var k = new c.lang.Event("onaddpoint");k.point = n;k.pixel = h._map.pointToPixel(n);k.index = h._points.length - 1;k.distance = h._getTotalDistance().toFixed(0);h.dispatchEvent(k)};var f = function(p) {if (!h._isOpen) {return}if (h._paths.length > 0) {p = window.event || p;var l = p.pageX || p.clientX || 0;var k = p.pageY || p.clientY || 0;if (typeof h._bind.initX == "undefined") {h._bind.x = p.layerX || p.offsetX || 0;h._bind.y = p.layerY || p.offsetY || 0;h._bind.initX = l;h._bind.initY = k}var r = h._bind.x + l - h._bind.initX;var q = h._bind.y + k - h._bind.initY;var z = h._paths[h._paths.length - 1];var m = h._map.pixelToPoint(new BMap.Pixel(r, q));z.setPositionAt(1, m);if (!h._mapMoving) {z.show()}var A = 0;var u = 0;if (r < 10) {A = 8} else {if (r > h._map.getSize().width - 10) {A = -8}}if (q < 10) {u = 8} else {if (q > h._map.getSize().height - 10) {u = -8}}if (A != 0 || u != 0) {if (!f._movingTimerId) {h._mapMoving = true;h._map.panBy(A, u, {noAnimation: true});h._movingTimerId = f._movingTimerId = setInterval(function() {h._map.panBy(A, u, {noAnimation: true})},30);z.hide();h._followTitle && h._followTitle.hide()}} else {if (f._movingTimerId) {clearInterval(f._movingTimerId);delete f._movingTimerId;delete h._movingTimerId;var w = h._paths[h._paths.length - 1];var v = h._map.pixelToPoint(new BMap.Pixel(r, q));if (!w) {return}w.setPositionAt(1, v);w.show();if (h._followTitle) {h._followTitle.setPosition(v);h._followTitle.show()}h._bind.i = 0;h._bind.j = 0;delete h._mapMoving}}if (h._followTitle) {var o = h._getTotalDistance();var n = h._map.getDistance(h._points[h._points.length - 1], m);h._updateInstDis(h._followTitle, o + n)}} else {if (h._followTitle) {h._followTitle.show();p = window.event || p;var s = p.target || p.srcElement;if (s != a.getDom()) {h._followTitle.hide()}}}};var e = function(k) {if (!h._isOpen) {return}c.un(a.getDom(h._map), "click", g);c.un(document, "mousemove", f);c.un(a.getDom(h._map), "dblclick", e);c.un(document, "keydown", j);c.un(a.getDom(h._map), "mouseup", i);setTimeout(function() {//1h.close()},50)};var j = function(k) {k = window.event || k;if (k.keyCode == 27) {h._clearCurData();setTimeout(function() {//2h.close()},50)}};var i = function(k) {k = window.event || k;var l = 0;if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {l = document.documentMode || +RegExp["\x241"]}if (l && k.button != 1 || k.button == 2) {//3h.close()}};h._initData();this._formatTitle();a.show(this._map);this._setCursor(this._opts.cursor);c.on(a.getDom(this._map), "click", g);c.on(document, "mousemove", f);c.on(a.getDom(this._map), "dblclick", e);c.on(document, "keydown", j);c.on(a.getDom(this._map), "mouseup", i);this.bindFunc = [{elem: a.getDom(this._map),type: "click",func: g},{elem: a.getDom(this._map),type: "dblclick",func: e},{elem: document,type: "mousemove",func: f},{elem: document,type: "keydown",func: j},{elem: a.getDom(this._map),type: "mouseup",func: i}];return true};d.prototype._dispatchLastEvent = function() {var e = new c.lang.Event("ondrawend");e.points = this._points ? this._points.slice(0) : [];e.overlays = this._paths ? this._paths.slice(0, this._paths.length - 1) : [];e.distance = this._getTotalDistance().toFixed(0);this.dispatchEvent(e)};d.prototype.close = function() {if (this._isOpen == false) {return}this._isOpen = false;BMapLib._toolInUse = false;if (this._mapMoving) {delete this._mapMoving}var g = this;g._dispatchLastEvent();if (g._points.length < 2) {g._clearCurData()} else {g._paths[g._paths.length - 1].remove();g._paths[g._paths.length - 1] = null;g._paths.length = g._paths.length - 1;var h = g._points[g._points.length - 1];if (h.disLabel) {h.disLabel.remove()}g._processLastOp()}a.hide();for (var f = 0,e = this.bindFunc.length; f < e; f++) {c.un(this.bindFunc[f].elem, this.bindFunc[f].type, this.bindFunc[f].func)}if (g._movingTimerId) {clearInterval(g._movingTimerId);g._movingTimerId = null}if (this._followTitle) {this._followTitle.hide()}};d.prototype._clearCurData = function() {for (var f = 0,e = this._points.length; f < e; f++) {if (this._points[f].disLabel) {this._points[f].disLabel.remove()}}for (var f = 0,e = this._paths.length; f < e; f++) {this._paths[f].remove()}for (var f = 0,e = this._dots.length; f < e; f++) {this._dots[f].remove()}this._initData()};d.prototype._initData = function() {this._points.length = 0;this._paths.length = 0;this._segDistance.length = 0;this._dots.length = 0};d.prototype._setSegDistance = function(g, f) {if (!g || !f) {return}var e = this._map.getDistance(g, f);this._segDistance.push(e);return e};d.prototype._getTotalDistance = function() {var g = 0;for (var f = 0,e = this._segDistance.length; f < e; f++) {g += this._segDistance[f]}return g};d.prototype._convertUnit = function(e, f) {f = f || "metric";if (this._units[f]) {return e * this._units[f].conv}return e};d.prototype._addSecPoint = function(g) {var f = this._opts.secIcon ? this._opts.secIcon: new BMap.Icon("http://api.map.baidu.com/images/mapctrls.png", new BMap.Size(11, 11), {imageOffset: new BMap.Size( - 26, -313)});var e = new BMap.Marker(g, {icon: f,clickable: false,baseZIndex: 3500000,zIndexFixed: true,enableMassClear: this._enableMassClear});this._map.addOverlay(e);this._dots.push(e)};d.prototype._formatDisStr = function(h) {var f = this._opts.unit;var g = this._units[f].u1;var e = this._convertUnit(h, f);if (e > this._units[f].incon) {e = e / this._units[f].incon;g = this._units[f].u2;e = e.toFixed(1)} else {e = e.toFixed(0)}return e + g};d.prototype._setCursor = function(f) {var e = /webkit/.test(navigator.userAgent.toLowerCase()) ? "url(" + this._opts.cursor + ") 3 6, crosshair": "url(" + this._opts.cursor + "), crosshair";a._setCursor(e)};d.prototype._getCursor = function() {return this._opts.cursor};d.prototype._formatSegLabel = function(e, f) {e.setStyle({border: "none",padding: "0"});e.setContent("<span style='" + this._styles.BMapLib_diso + "'><span style='" + this._styles.BMapLib_disi + "'>" + f + "</span></span>")};d.prototype._processLastOp = function() {var i = this;delete i._bind.x;delete i._bind.y;delete i._bind.initX;delete i._bind.initY;if (i._paths.length > i._points.length - 1) {var g = i._paths.length - 1;i._paths[g].remove();i._paths[g] = null;i._paths.length = g}var e = {};e.points = i._points.slice(0);e.paths = i._paths.slice(0);e.dots = i._dots.slice(0);e.segDis = i._segDistance.slice(0);var j = i._map.pointToPixel(e.points[e.points.length - 1]);var h = i._map.pointToPixel(e.points[e.points.length - 2]);var k = [0, 0];var f = [0, 0];if (j.y - h.y >= 0) {f = [ - 5, 11]} else {f = [ - 5, -35]}if (j.x - h.x >= 0) {k = [14, 0]} else {k = [ - 14, 0]}var n = e.points[e.points.length - 1];n.disLabel = new BMap.Label("", {offset: new BMap.Size( - 15, -40),enableMassClear: i._enableMassClear});n.disLabel.setStyles({color: "#333",borderColor: "#ff0103"});i._map.addOverlay(n.disLabel);n.disLabel.setOffset(new BMap.Size(f[0], f[1]));n.disLabel.setPosition(n);i._formatTitle(2, "", "", n.disLabel);var m = this._opts.closeIcon ? this._opts.closeIcon: new BMap.Icon("http://api.map.baidu.com/images/mapctrls.gif", new BMap.Size(12, 12), {imageOffset: new BMap.Size(0, -14)});e.closeBtn = new BMap.Marker(e.points[e.points.length - 1], {icon: m,offset: new BMap.Size(k[0], k[1]),baseZIndex: 3600000,enableMassClear: i._enableMassClear});//将多边形绑定到关闭按钮上var hh = this;e.closeBtn._polygon = hh.polygon;hh.polygon = undefined;hh._areaPoints = undefined;i._map.addOverlay(e.closeBtn);//绑定添加焦点事件e.closeBtn.setTitle("\u6e05\u9664\u672c\u6b21\u6d4b\u8ddd");e.closeBtn.addEventListener("click",function(r) {//TODOvar polygon = r.target._polygon;if(polygon.label!=undefined){hh._map.removeOverlay(polygon.label);}hh._map.removeOverlay(polygon);r.target._polygon =undefined;for (var p = 0,o = e.points.length; p < o; p++) {e.points[p].disLabel.remove();e.points[p].disLabel = null}for (var p = 0,o = e.paths.length; p < o; p++) {e.paths[p].remove();e.paths[p] = null}for (var p = 0,o = e.dots.length; p < o; p++) {e.dots[p].remove();e.dots[p] = null}e.closeBtn.remove();e.closeBtn = null;b(r);var q = new c.lang.Event("onremovepolyline");i.dispatchEvent(q)//todo});i._initData()};d.prototype._formatTitle = function(g, l, e, i) {var h = i || this._followTitle;if (!h) {return}h.setStyle({lineHeight: "16px",zIndex: "85",padding: "3px 5px"});var n = this._startFollowText || "";var k = [];if (g == 1) {h.setOffset(0, 25);var m = this._opts.unit;var j = this._units[m].u1;var f = this._convertUnit(e, m);if (f > this._units[m].incon) {f = f / this._units[m].incon;j = this._units[m].u2;f = f.toFixed(1)} else {f = f.toFixed(0)}k.push("<span>\u603b\u957f\uff1a<span style='" + this._styles.BMapLib_disBoxDis + "'>" + f + "</span>" + j + "</span><br />");k.push("<span style='color:#7a7a7a'>" + l + "</span>")} else {if (g == 2) {var m = this._opts.unit;var j = this._units[m].u1;var f = this._convertUnit(this._getTotalDistance(), m);if (f > this._units[m].incon) {f = f / this._units[m].incon;j = this._units[m].u2;f = f.toFixed(1)} else {f = f.toFixed(0)}k.push("\u603b\u957f\uff1a<span style='" + this._styles.BMapLib_disBoxDis + "'>" + f + "</span>" + j)} else {h.setOffset(0, 25);k.push(n)}}h.setContent(k.join(""))};d.prototype._updateInstDis = function(g, e) {var f = this._opts.unit;var i = this._units[f].u1;if (e > this._units[f].incon) {e = e / this._units[f].incon;i = this._units[f].u2;e = e.toFixed(1)} else {e = e.toFixed(0)}if (g) {var h = [];h.push("<span>\u603b\u957f\uff1a<span style='" + this._styles.BMapLib_disBoxDis + "'>" + e + "</span>" + i + "</span><br />");h.push("<span style='color:#7a7a7a'>" + this._opts.followText + "</span>");g.setContent(h.join(""))}};d.prototype._hideCurrent = function() {if (!this._isOpen) {return}if (this._paths.length > 0) {var e = this._paths[this._paths.length - 1];e.hide()}this._followTitle && this._followTitle.hide()};d.prototype._isPointValid = function(h) {if (!h) {return false}var f = this._map.getBounds();var e = f.getSouthWest(),g = f.getNorthEast();if (h.lng < e.lng || h.lng > g.lng || h.lat < e.lat || h.lat > g.lat) {return false}return true};var a = {_map: null,_html: "<div style='background:transparent url(http://api.map.baidu.com/images/blank.gif);position:absolute;left:0;top:0;width:100%;height:100%;z-index:1000' unselectable='on'></div>",_maskElement: null,_cursor: "default",_inUse: false,show: function(e) {if (!this._map) {this._map = e}this._inUse = true;if (!this._maskElement) {this._createMask(e)}this._maskElement.style.display = "block"},_createMask: function(g) {this._map = g;if (!this._map) {return}c.insertHTML(this._map.getContainer(), "beforeEnd", this._html);var f = this._maskElement = this._map.getContainer().lastChild;var e = function(h) {b(h);return c.preventDefault(h)};c.on(f, "mouseup",function(h) {if (h.button == 2) {e(h)}});c.on(f, "contextmenu", e);f.style.display = "none"},getDrawPoint: function(h, j) {h = window.event || h;var f = h.layerX || h.offsetX || 0;var i = h.layerY || h.offsetY || 0;var g = h.target || h.srcElement;if (g != a.getDom(this._map) && j == true) {while (g && g != this._map.getContainer()) {if (! (g.clientWidth == 0 && g.clientHeight == 0 && g.offsetParent && g.offsetParent.nodeName.toLowerCase() == "td")) {f += g.offsetLeft;i += g.offsetTop}g = g.offsetParent}}if (g != a.getDom(this._map) && g != this._map.getContainer()) {return}if (typeof f === "undefined" || typeof i === "undefined") {return}if (isNaN(f) || isNaN(i)) {return}return this._map.pixelToPoint(new BMap.Pixel(f, i))},hide: function() {if (!this._map) {return}this._inUse = false;if (this._maskElement) {this._maskElement.style.display = "none"}},getDom: function(e) {if (!this._maskElement) {this._createMask(e)}return this._maskElement},_setCursor: function(e) {this._cursor = e || "default";if (this._maskElement) {this._maskElement.style.cursor = this._cursor}}};function b(f) {var f = window.event || f;f.stopPropagation ? f.stopPropagation() : f.cancelBubble = true}
})();var _polygonStyleOptions = { strokeColor:"blue", //边线颜色。 fillColor:"#FFCCFF", //填充颜色。当参数为空时,圆形将没有填充效果。 strokeWeight: 0.00001, //边线的宽度,以像素为单位。 strokeOpacity: 0, //边线透明度,取值范围0 - 1。 fillOpacity: 0.3, //填充的透明度,取值范围0 - 1。 strokeStyle: 'solid' //边线的样式,solid或dashed。
}
var _LabelOptions = { color : "black", fontSize : "16px", fillColor:"red" //填充颜色。当参数为空时,圆形将没有填充效果。
} //自定义测量面积工具
var createMeasureAreaTool =function(map){var myDis = new BMapLib.MeasureAreaTool(map); //测距插件myDis.addEventListener("addpoint", function(e) {var _map = e.target._map;if(e.target._areaPoints == undefined){e.target._areaPoints = new Array();}e.target._areaPoints.push(e.point);if(e.target.polygon == undefined){var polygon = new BMap.Polygon(e.target._areaPoints,_polygonStyleOptions);myDis.polygon = polygon;_map.addOverlay(polygon);}else{var polygon = e.target.polygon;polygon.setPath(e.target._areaPoints);//计算多边形的面积var _area = 0;_area = BMapLib.GeoUtils.getPolygonArea(polygon);//保留两位小数_area = _area.toFixed(2);//获取多边形的中心var _paths = polygon.getPath();var point = getCenterPoint(_paths);//移除polygon之前的labelif(polygon.label!=undefined){var l = polygon.label;_map.removeOverlay(l);polygon.label = undefined;}//往多边形添加标注var label = new BMap.Label("区域面积:"+_area+"m2",_LabelOptions);polygon.label =label;label.setPosition(point);//往地图上添加标注_map.addOverlay(label);}}); return myDis;
}
2.3 GeoUtils.js 这个是计算面积的api,这个也是必须的,代码如下:
/**
* @fileoverview GeoUtils类提供若干几何算法,用来帮助用户判断点与矩形、
* 圆形、多边形线、多边形面的关系,并提供计算折线长度和多边形的面积的公式。
* 主入口类是<a href="symbols/BMapLib.GeoUtils.html">GeoUtils</a>,
* 基于Baidu Map API 1.2。
*
* @author Baidu Map Api Group
* @version 1.2
*/ //BMapLib.GeoUtils.degreeToRad(Number)
//将度转化为弧度 //BMapLib.GeoUtils.getDistance(Point, Point)
//计算两点之间的距离,两点坐标必须为经纬度 //BMapLib.GeoUtils.getPolygonArea(polygon)
//计算多边形面或点数组构建图形的面积,注意:坐标类型只能是经纬度,且不适合计算自相交多边形的面积(封闭的面积) //BMapLib.GeoUtils.getPolylineDistance(polyline)
//计算折线或者点数组的长度 //BMapLib.GeoUtils.isPointInCircle(point, circle)
//判断点是否在圆形内 //BMapLib.GeoUtils.isPointInPolygon(point, polygon)
//判断点是否多边形内 //BMapLib.GeoUtils.isPointInRect(point, bounds)
//判断点是否在矩形内 //BMapLib.GeoUtils.isPointOnPolyline(point, polyline)
//判断点是否在折线上 //BMapLib.GeoUtils.radToDegree(Number)
//将弧度转化为度 function getCenterPoint(path){//var path = e.;//Array<Point> 返回多边型的点数组//var ret=parseFloat(num1)+parseFloat(num2); var x = 0.0;var y = 0.0;for(var i=0;i<path.length;i++){x=x+ parseFloat(path[i].lng);y=y+ parseFloat(path[i].lat);}x=x/path.length;y=y/path.length;return new BMap.Point(x,y);}/**
* @namespace BMap的所有library类均放在BMapLib命名空间下
*/
var BMapLib = window.BMapLib = BMapLib || {};
(function () { /** * 地球半径 */ var EARTHRADIUS = 6370996.81; /** * @exports GeoUtils as BMapLib.GeoUtils */ var GeoUtils = /** * GeoUtils类,静态类,勿需实例化即可使用 * @class GeoUtils类的<b>入口</b>。 * 该类提供的都是静态方法,勿需实例化即可使用。 */ BMapLib.GeoUtils = function () { } /** * 判断点是否在矩形内 * @param {Point} point 点对象 * @param {Bounds} bounds 矩形边界对象 * @returns {Boolean} 点在矩形内返回true,否则返回false */ GeoUtils.isPointInRect = function (point, bounds) { //检查类型是否正确 if (!(point instanceof BMap.Point) || !(bounds instanceof BMap.Bounds)) { return false; } var sw = bounds.getSouthWest(); //西南脚点 var ne = bounds.getNorthEast(); //东北脚点 return (point.lng >= sw.lng && point.lng <= ne.lng && point.lat >= sw.lat && point.lat <= ne.lat); } /** * 判断点是否在圆形内 * @param {Point} point 点对象 * @param {Circle} circle 圆形对象 * @returns {Boolean} 点在圆形内返回true,否则返回false */ GeoUtils.isPointInCircle = function (point, circle) { //检查类型是否正确 if (!(point instanceof BMap.Point) || !(circle instanceof BMap.Circle)) { return false; } //point与圆心距离小于圆形半径,则点在圆内,否则在圆外 var c = circle.getCenter(); var r = circle.getRadius(); var dis = GeoUtils.getDistance(point, c); if (dis <= r) { return true; } else { return false; } } /** * 判断点是否在折线上 * @param {Point} point 点对象 * @param {Polyline} polyline 折线对象 * @returns {Boolean} 点在折线上返回true,否则返回false */ GeoUtils.isPointOnPolyline = function (point, polyline) { //检查类型 if (!(point instanceof BMap.Point) || !(polyline instanceof BMap.Polyline)) { return false; } //首先判断点是否在线的外包矩形内,如果在,则进一步判断,否则返回false var lineBounds = polyline.getBounds(); if (!this.isPointInRect(point, lineBounds)) { return false; } //判断点是否在线段上,设点为Q,线段为P1P2 , //判断点Q在该线段上的依据是:( Q - P1 ) × ( P2 - P1 ) = 0,且 Q 在以 P1,P2为对角顶点的矩形内 var pts = polyline.getPath(); for (var i = 0; i < pts.length - 1; i++) { var curPt = pts[i]; var nextPt = pts[i + 1]; //首先判断point是否在curPt和nextPt之间,即:此判断该点是否在该线段的外包矩形内 if (point.lng >= Math.min(curPt.lng, nextPt.lng) && point.lng <= Math.max(curPt.lng, nextPt.lng) && point.lat >= Math.min(curPt.lat, nextPt.lat) && point.lat <= Math.max(curPt.lat, nextPt.lat)) { //判断点是否在直线上公式 var precision = (curPt.lng - point.lng) * (nextPt.lat - point.lat) - (nextPt.lng - point.lng) * (curPt.lat - point.lat); if (precision < 2e-10 && precision > -2e-10) {//实质判断是否接近0 return true; } } } return false; } /** * 判断点是否多边形内 * @param {Point} point 点对象 * @param {Polyline} polygon 多边形对象 * @returns {Boolean} 点在多边形内返回true,否则返回false */ GeoUtils.isPointInPolygon = function (point, polygon) { //检查类型 if (!(point instanceof BMap.Point) || !(polygon instanceof BMap.Polygon)) { return false; } //首先判断点是否在多边形的外包矩形内,如果在,则进一步判断,否则返回false var polygonBounds = polygon.getBounds(); if (!this.isPointInRect(point, polygonBounds)) { return false; } var pts = polygon.getPath(); //获取多边形点 //下述代码来源:http://paulbourke.net/geometry/insidepoly/,进行了部分修改 //基本思想是利用射线法,计算射线与多边形各边的交点,如果是偶数,则点在多边形外,否则 //在多边形内。还会考虑一些特殊情况,如点在多边形顶点上,点在多边形边上等特殊情况。 var N = pts.length; var boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true var intersectCount = 0; //cross points count of x var precision = 2e-10; //浮点类型计算时候与0比较时候的容差 var p1, p2; //neighbour bound vertices var p = point; //测试点 p1 = pts[0]; //left vertex for (var i = 1; i <= N; ++i) {//check all rays if (p.equals(p1)) { return boundOrVertex; //p is an vertex } p2 = pts[i % N]; //right vertex if (p.lat < Math.min(p1.lat, p2.lat) || p.lat > Math.max(p1.lat, p2.lat)) {//ray is outside of our interests p1 = p2; continue; //next ray left point } if (p.lat > Math.min(p1.lat, p2.lat) && p.lat < Math.max(p1.lat, p2.lat)) {//ray is crossing over by the algorithm (common part of) if (p.lng <= Math.max(p1.lng, p2.lng)) {//x is before of ray if (p1.lat == p2.lat && p.lng >= Math.min(p1.lng, p2.lng)) {//overlies on a horizontal ray return boundOrVertex; } if (p1.lng == p2.lng) {//ray is vertical if (p1.lng == p.lng) {//overlies on a vertical ray return boundOrVertex; } else {//before ray ++intersectCount; } } else {//cross point on the left side var xinters = (p.lat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng; //cross point of lng if (Math.abs(p.lng - xinters) < precision) {//overlies on a ray return boundOrVertex; } if (p.lng < xinters) {//before ray ++intersectCount; } } } } else {//special case when ray is crossing through the vertex if (p.lat == p2.lat && p.lng <= p2.lng) {//p crossing over p2 var p3 = pts[(i + 1) % N]; //next vertex if (p.lat >= Math.min(p1.lat, p3.lat) && p.lat <= Math.max(p1.lat, p3.lat)) {//p.lat lies between p1.lat & p3.lat ++intersectCount; } else { intersectCount += 2; } } } p1 = p2; //next ray left point } if (intersectCount % 2 == 0) {//偶数在多边形外 return false; } else { //奇数在多边形内 return true; } } /** * 将度转化为弧度 * @param {degree} Number 度 * @returns {Number} 弧度 */ GeoUtils.degreeToRad = function (degree) { return Math.PI * degree / 180; } /** * 将弧度转化为度 * @param {radian} Number 弧度 * @returns {Number} 度 */ GeoUtils.radToDegree = function (rad) { return (180 * rad) / Math.PI; } /** * 将v值限定在a,b之间,纬度使用 */ function _getRange(v, a, b) { if (a != null) { v = Math.max(v, a); } if (b != null) { v = Math.min(v, b); } return v; } /** * 将v值限定在a,b之间,经度使用 */ function _getLoop(v, a, b) { while (v > b) { v -= b - a } while (v < a) { v += b - a } return v; } /** * 计算两点之间的距离,两点坐标必须为经纬度 * @param {point1} Point 点对象 * @param {point2} Point 点对象 * @returns {Number} 两点之间距离,单位为米 */ GeoUtils.getDistance = function (point1, point2) { //判断类型 if (!(point1 instanceof BMap.Point) || !(point2 instanceof BMap.Point)) { return 0; } point1.lng = _getLoop(point1.lng, -180, 180); point1.lat = _getRange(point1.lat, -74, 74); point2.lng = _getLoop(point2.lng, -180, 180); point2.lat = _getRange(point2.lat, -74, 74); var x1, x2, y1, y2; x1 = GeoUtils.degreeToRad(point1.lng); y1 = GeoUtils.degreeToRad(point1.lat); x2 = GeoUtils.degreeToRad(point2.lng); y2 = GeoUtils.degreeToRad(point2.lat); return EARTHRADIUS * Math.acos((Math.sin(y1) * Math.sin(y2) + Math.cos(y1) * Math.cos(y2) * Math.cos(x2 - x1))); } /** * 计算折线或者点数组的长度 * @param {Polyline|Array<Point>} polyline 折线对象或者点数组 * @returns {Number} 折线或点数组对应的长度 */ GeoUtils.getPolylineDistance = function (polyline) { //检查类型 if (polyline instanceof BMap.Polyline || polyline instanceof Array) { //将polyline统一为数组 var pts; if (polyline instanceof BMap.Polyline) { pts = polyline.getPath(); } else { pts = polyline; } if (pts.length < 2) {//小于2个点,返回0 return 0; } //遍历所有线段将其相加,计算整条线段的长度 var totalDis = 0; for (var i = 0; i < pts.length - 1; i++) { var curPt = pts[i]; var nextPt = pts[i + 1] var dis = GeoUtils.getDistance(curPt, nextPt); totalDis += dis; } return totalDis; } else { return 0; } } /** * 计算多边形面或点数组构建图形的面积,注意:坐标类型只能是经纬 度,且不适合计算自相交多边形的面积 * @param {Polygon|Array<Point>} polygon 多边形面对象或者点数 组 * @returns {Number} 多边形面或点数组构成图形的面积 */ GeoUtils.getPolygonArea = function (polygon) { //检查类型 if (!(polygon instanceof BMap.Polygon) && !(polygon instanceof Array)) { return 0; } var pts; if (polygon instanceof BMap.Polygon) { pts = polygon.getPath(); } else { pts = polygon; } if (pts.length < 3) {//小于3个顶点,不能构建面 return 0; } var totalArea = 0; //初始化总面积 var LowX = 0.0; var LowY = 0.0; var MiddleX = 0.0; var MiddleY = 0.0; var HighX = 0.0; var HighY = 0.0; var AM = 0.0; var BM = 0.0; var CM = 0.0; var AL = 0.0; var BL = 0.0; var CL = 0.0; var AH = 0.0; var BH = 0.0; var CH = 0.0; var CoefficientL = 0.0; var CoefficientH = 0.0; var ALtangent = 0.0; var BLtangent = 0.0; var CLtangent = 0.0; var AHtangent = 0.0; var BHtangent = 0.0; var CHtangent = 0.0; var ANormalLine = 0.0; var BNormalLine = 0.0; var CNormalLine = 0.0; var OrientationValue = 0.0; var AngleCos = 0.0; var Sum1 = 0.0; var Sum2 = 0.0; var Count2 = 0; var Count1 = 0; var Sum = 0.0; var Radius = EARTHRADIUS; //6378137.0,WGS84椭球半径 var Count = pts.length; for (var i = 0; i < Count; i++) { if (i == 0) { LowX = pts[Count - 1].lng * Math.PI / 180; LowY = pts[Count - 1].lat * Math.PI / 180; MiddleX = pts[0].lng * Math.PI / 180; MiddleY = pts[0].lat * Math.PI / 180; HighX = pts[1].lng * Math.PI / 180; HighY = pts[1].lat * Math.PI / 180; } else if (i == Count - 1) { LowX = pts[Count - 2].lng * Math.PI / 180; LowY = pts[Count - 2].lat * Math.PI / 180; MiddleX = pts[Count - 1].lng * Math.PI / 180; MiddleY = pts[Count - 1].lat * Math.PI / 180; HighX = pts[0].lng * Math.PI / 180; HighY = pts[0].lat * Math.PI / 180; } else { LowX = pts[i - 1].lng * Math.PI / 180; LowY = pts[i - 1].lat * Math.PI / 180; MiddleX = pts[i].lng * Math.PI / 180; MiddleY = pts[i].lat * Math.PI / 180; HighX = pts[i + 1].lng * Math.PI / 180; HighY = pts[i + 1].lat * Math.PI / 180; } AM = Math.cos(MiddleY) * Math.cos(MiddleX); BM = Math.cos(MiddleY) * Math.sin(MiddleX); CM = Math.sin(MiddleY); AL = Math.cos(LowY) * Math.cos(LowX); BL = Math.cos(LowY) * Math.sin(LowX); CL = Math.sin(LowY); AH = Math.cos(HighY) * Math.cos(HighX); BH = Math.cos(HighY) * Math.sin(HighX); CH = Math.sin(HighY); CoefficientL = (AM * AM + BM * BM + CM * CM) / (AM * AL + BM * BL + CM * CL); CoefficientH = (AM * AM + BM * BM + CM * CM) / (AM * AH + BM * BH + CM * CH); ALtangent = CoefficientL * AL - AM; BLtangent = CoefficientL * BL - BM; CLtangent = CoefficientL * CL - CM; AHtangent = CoefficientH * AH - AM; BHtangent = CoefficientH * BH - BM; CHtangent = CoefficientH * CH - CM; AngleCos = (AHtangent * ALtangent + BHtangent * BLtangent + CHtangent * CLtangent) / (Math.sqrt(AHtangent * AHtangent + BHtangent * BHtangent + CHtangent * CHtangent) * Math.sqrt(ALtangent * ALtangent + BLtangent * BLtangent + CLtangent * CLtangent)); AngleCos = Math.acos(AngleCos); ANormalLine = BHtangent * CLtangent - CHtangent * BLtangent; BNormalLine = 0 - (AHtangent * CLtangent - CHtangent * ALtangent); CNormalLine = AHtangent * BLtangent - BHtangent * ALtangent; if (AM != 0) OrientationValue = ANormalLine / AM; else if (BM != 0) OrientationValue = BNormalLine / BM; else OrientationValue = CNormalLine / CM; if (OrientationValue > 0) { Sum1 += AngleCos; Count1++; } else { Sum2 += AngleCos; Count2++; } } var tempSum1, tempSum2; tempSum1 = Sum1 + (2 * Math.PI * Count2 - Sum2); tempSum2 = (2 * Math.PI * Count1 - Sum1) + Sum2; if (Sum1 > Sum2) { if ((tempSum1 - (Count - 2) * Math.PI) < 1) Sum = tempSum1; else Sum = tempSum2; } else { if ((tempSum2 - (Count - 2) * Math.PI) < 1) Sum = tempSum2; else Sum = tempSum1; } totalArea = (Sum - (Count - 2) * Math.PI) * Radius * Radius; return totalArea; //返回总面积 } })(); //闭包结束
GeoUtilsAPI文档地址:http://api.map.baidu.com/library/GeoUtils/1.2/docs/symbols/BMapLib.GeoUtils.html
好了,现在可以测试效果了,浏览器打开measureAreaTool_baidu.html这个页面,点击面积测量就可以看到效果。
代码下载地址:https://download.csdn.net/download/hgq0916/12403463
本人水平有限,代码有不足之处还请大家见谅,欢迎大家提建议。本人目前主要方向是Java,如果有兴趣,可以一起交流,
Java成长交流学习群:184998348