【地图扩展开发】一、曲线覆盖物

  1. 1. 起因
  2. 2. 原理
  3. 3. 特性
  4. 4. 实例开发
    1. 4.1. 百度地图
    2. 4.2. 高德地图
  5. 5. 总结

文章所有涉及到的内容均可以在 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
// 挂载SVG控制库到百度地图对象上
BMap.Raphael = BMap.Raphael || Raphael;

// 创建曲线绘制命令对象
// 使用 SVGPATH 命令进行曲线绘制
function CurveCommand(c,params){
// 命令参数 目前支持M和C
this._c = c;
// 命令具体参数
this._params = params;
}
// 挂载曲线命令对象到百度地图对象上
BMap.CurveCommand = CurveCommand;

// 创建曲线类
function Curve(commandList,opts){
// 命令列表
this._cl = commandList;
// 样式
this._opts = opts;
// 显示标识
// this._show = false;
var me = this;
// 移除事件
function removeEvent(){
me._map = null;
this.removeEventListener('remove',removeEvent)
}
this.addEventListener('remove',removeEvent);
}
// 将曲线对象挂载到百度地图覆盖物上
Curve.prototype = new BMap.Overlay();

// 通过命令列表获得真正的用于绘制的SVGPATH命令
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号更新的贝塞尔曲线,我自己心里还是很欣慰的。因为那个时候的需求如今终于被官方实现了。

欢迎访问博客地址:https://www.zhoyq.com