文章所有涉及到的内容均可以在 https://gitee.com/zhoyq/examples/tree/master/mapExt 中获取。本文会先后以百度地图v3.0和高德地图v1.4.5为基础进行进行开发。
起因
因为之前一直使用地图方面的API开发网站,有时候会看到地图API画出来的圆形有棱角,感觉像是折线扩展,经过翻查百度地图以及高德地图的源代码,才发现真的是使用折线实现的。有时候需要几率很准确的曲线甚至有曲率等数据,所以萌生了开发曲线覆盖物的想法。
原理
地图上的图形都是缩放不改变精度的,所以还是使用SVG开发比较好,为了尽可能好的完成项目,避开问题,使用了一个SVG控制的库RaphaelJs
,通过地图中的自定义图层挂载SVG图层,完成绘制以及缩放等功能。
特性
实现了SVG PATH中的C和M命令,可以绘制简单的曲线(可以在此基础上实现更多命令);
实例开发
百度地图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| BMap.Raphael = BMap.Raphael || Raphael; function CurveCommand(c,params){ this._c = c; this._params = params; } BMap.CurveCommand = CurveCommand;
function Curve(commandList,opts){ this._cl = commandList; this._opts = opts; var me = this; function removeEvent(){ me._map = null; this.removeEventListener('remove',removeEvent) } this.addEventListener('remove',removeEvent); } Curve.prototype = new BMap.Overlay();
Curve.prototype.__getSvgPath = function(){ var buf = ''; for(var i = 0;i<this._cl.length;i++){ var cc = this._cl[i]; buf += cc._c; for(var j=0;j<cc._params.length;j++){ var pbuf = this._map.pointToOverlayPixel(cc._params[j]); buf += pbuf.x+" "+pbuf.y; if(j!=cc._params.length-1){ buf += " "; } } } return buf; };
Curve.prototype.initialize = function(map){ this._map = map; var svgP = this.__getSvgPath(); var div = this.container = document.createElement('div'); div.style.cssText = 'position:absolute;top:0px;left:0px;z-index:199;'; this._paper = BMap.Raphael(div,1800,1600); this._paper.setViewBox(-500,-500,1800,1600); this.obj = this._paper.path(svgP); if(this._opts){ this.obj.attr(this._opts); }else{ this.obj.attr({ "stroke-width":4, "cursor":"pointer", "stroke":"#3a6bdb", "stroke-opacity":0.7 }); } this._map.getPanes().markerPane.appendChild(div); div.firstChild.style.cssText='position:absolute;top:-500px;left:-500px;width:1800px;height:1600px;'; return div; };
Curve.prototype.draw = function(){ var map = this._map, point = map.pixelToPoint(new BMap.Pixel(0, 0)), pixel = map.pointToOverlayPixel(point); this.container.firstChild.style.left = (pixel.x-500) + "px"; this.container.firstChild.style.top = (pixel.y-500) + "px"; this._paper.setViewBox(pixel.x-500,pixel.y-500,1800,1600); var svgPath = this.__getSvgPath(); this.obj.attr({ path:svgPath }); };
Curve.prototype.getMap = function(){ return this._map; };
Curve.prototype.getCommandList = function(){ return this._cl; };
Curve.prototype.setCommandList = function(cl){ this._cl = cl; var svgPath = this.__getSvgPath(); this.obj[0].setAttribute('d',svgPath); }; BMap.Curve = Curve;
|
源码 实例
注意:百度地图直接使用这段代码时,使用缩放会出现中心点漂移的现象,主要原因是中心点计算出现的问题,需要在源代码的基础上添加一行代码解决这个bug new BMap.Polyline([new BMap.Point(116.404, 39.905),new BMap.Point(116.414, 39.905)]).hide();
。
高德地图
最近看了1.4.5版本的地图API,高德居然自己实现了贝塞尔曲线,值得点赞。那就可以使用原生API了,这里就不再另外实现。也不要说希望百度跟上脚步,发展还是要看需求,也许百度用户对曲线的要求并不高。
总结
总结来看,高德还是与时俱进的,更新稳定而高效。相比之下百度地图API却迟迟变化不大。但是实际使用的时候,我更喜欢百度API这种对二次开发友好的接口设计,暴露一些底层类提供实现,这样我们自己就能定义自己的组件库了,并不是说高德的插件模式不好,见仁见智吧。我自己还是喜欢对象继承这种扩展模式,在javascript里增加类体系本身就让我觉得高兴。
PS. 我看了一下高德地图的API更新,2017年11月29号更新的贝塞尔曲线,我自己心里还是很欣慰的。因为那个时候的需求如今终于被官方实现了。