OpenLayers源码学习15:地图Map_1

年后上班了, 这年过的比较累 各种串门…
这个map类估计一次看不完, 分几次慢慢看吧

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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//OpenLayers.Map的实例, 注释说此类中只有必要方法(其实三千行...), 还需要配合OpenLayers.Control对地图进行操作
OpenLayers.Map = OpenLayers.Class({
//不同class的z-index配置
Z_INDEX_BASE: {
BaseLayer: 100,
Overlay: 325,
Feature: 725,
Popup: 750,
Control: 1000
},
/**
* Register a listener for a particular event with the following syntax:
* (code)
* map.events.register(type, obj, listener);
* (end)
*
* 支持的map事件类型:
* preaddlayer ,addlayer ,preremovelayer ,removelayer ,changelayer, movestart
* move,moveend,zoomend, mouseover, mouseout, mousemove, changebaselayer, updatesize
*/
//map的唯一id
id: null,
//分数zoom值, base layer是否支持分数zoom值
fractionalZoom: false,
//map对象持有的OpenLayers.Events实例
events: null,
//如果为true, 绘制过程中最底层的layer就变成base layer了
allOverlays: false,
//map的包裹div, 应该在构造函数里指定 或者用render方法(如果调用render就不能用<maxResolution> auto, 必须指定)
div: null,
//map当前是否正在被拖拽标志
dragging: false,
//当前map对象的 this.div{<OpenLayers.Size>}
size: null,
//map的viewport
viewPortDiv: null,
// 在zoom后图层容器的lonlat
layerContainerOrigin: null,
//图层的容器div
layerContainerDiv: null,
// <OpenLayers.Layer>的数组
layers: null,
// <OpenLayers.Control>数组, 如果没在构造里指定, 则默认有
/* - <OpenLayers.Control.Navigation> or <OpenLayers.Control.TouchNavigation>
* - <OpenLayers.Control.Zoom> or <OpenLayers.Control.PanZoom>
* - <OpenLayers.Control.ArgParser>
* - <OpenLayers.Control.Attribution>
*/
controls: null,
//<OpenLayers.Popup>数组
popups: null,
//当前选择的base layer<OpenLayers.Layer>
baseLayer: null,
//缓存地图中心点<OpenLayers.LonLat>
center: null,
//缓存分辨率
resolution: null,
//缓存zoom值
zoom: 0,
// 当前extent和panning的比值
panRatio: 1.5,
//缓存options对象(只读), 通过构造传进来
options: null,
// Options
//瓦片尺寸 <OpenLayers.Size>
tileSize: null,
//默认投影是经纬度, 用其他投影如墨卡托需要设置maxExtent, maxResolution.
//投影由当前的baseLayer决定(see <baseLayer> and <getProjectionObject>).
projection: "EPSG:4326",
//单位 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
units: null,
//分辨率数组(map units per pixel)
resolutions: null,
//最大分辨率
maxResolution: null,
//最小分辨率
minResolution: null,
//最大缩放
maxScale: null,
//最小缩放
minScale: null,
// 最大范围. 如果是数组 则顺序为(left, bottom, right, top) , 否则是<OpenLayers.Bounds>
maxExtent: null,
//最小范围
minExtent: null,
// 受限范围, 地图中心点将会被限制在此范围内. 要是想限制zoom的分辨率要用maxResolution
restrictedExtent: null,
// zoom等级数
numZoomLevels: 16,
//css风格
theme: null,
// 显示投影<OpenLayers.Projection>
displayProjection: null,
/**
* APIProperty: tileManager
* {<OpenLayers.TileManager>|Object} By default, and if the build contains
* TileManager.js, the map will use the TileManager to queue image requests
* and to cache tile image elements. To create a map without a TileManager
* configure the map with tileManager: null. To create a TileManager with
* non-default options, supply the options instead or alternatively supply
* an instance of {<OpenLayers.TileManager>}.
*/
// 是否把map接收的事件继续传递到当前页面上. 默认接收完阻止掉
fallThrough: false,
// resize事件触发时, 是否重新调整map的大小
autoUpdateSize: true,
// 随构造传入的监听器会被注册到<OpenLayers.Events.on>
eventListeners: null,
// 移动中心点后的<OpenLayers.Tween>动画对象see panTo(), 这个动画之前没看
panTween: null,
//移动中心点时候的动画, "null"可以关掉动画
panMethod: OpenLayers.Easing.Expo.easeOut,
//动画步长参数
panDuration: 50,
//zoom时候的动画策略 <OpenLayers.Tween>
zoomTween: null,
//缩放动画
zoomMethod: OpenLayers.Easing.Quad.easeOut,
//zoom动画持续步长
zoomDuration: 20,
//气泡外围的padding值
paddingForPopups : null,
// 图层容器得起始位置px
layerContainerOriginPx: null,
//最下最左值 , maxExtent和viewport的像素空隙 x,y
minPx: null,
//最顶最右值 , maxExtent和viewport的像素空隙 x,y
maxPx: null,
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* 创建一个新<OpenLayers.Map>实例
*
* 参数:
* div - {DOMElement|String} 地图所处div或div的id
* options - {Object} 配置对象
*
* 可以包含以下参数:
* center - {<OpenLayers.LonLat>|Array} 地图中心点
* zoom - {Number} 默认zoom值
* extent - {<OpenLayers.Bounds>|Array} 初始化范围, center和zoom指定的话这个就无效了
*
* 代码示例:
* var map = new OpenLayers.Map({
* div: "map_id",
* projection: "EPSG:3857",
* maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],
* restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],
* center: [-12356463.476333, 5621521.4854095]
* });
*
* //没给中心点, 需要创建完再render一下
* var map = new OpenLayers.Map({
* projection: "EPSG:3857",
* maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000)
* });
*/
initialize: function (div, options) {
//就一个参数的情况, 就像示例1. div实际上是参数对象的"div"项
if(arguments.length === 1 && typeof div === "object") {
options = div;
div = options && options.div;
}
//读取OpenLayers.Map.里的配置项
this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
OpenLayers.Map.TILE_HEIGHT);
//默认气泡的padding是15
this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
//默认css风格
this.theme = OpenLayers._getScriptLocation() +
'theme/default/style.css';
//缓存最原始的options, 用Util.extend闭包缓存
this.options = OpenLayers.Util.extend({}, options);
//覆盖掉this里的默认配置
OpenLayers.Util.extend(this, options);
//查询到projCode
var projCode = this.projection instanceof OpenLayers.Projection ?
this.projection.projCode : this.projection;
OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);
//最大 最小 受限范围, 统一处理<OpenLayers.Bounds>或数组
if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {
this.maxExtent = new OpenLayers.Bounds(this.maxExtent);
}
if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) {
this.minExtent = new OpenLayers.Bounds(this.minExtent);
}
if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) {
this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent);
}
if (this.center && !(this.center instanceof OpenLayers.LonLat)) {
this.center = new OpenLayers.LonLat(this.center);
}
//准备一个新数组
this.layers = [];
//唯一id
this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
//map需要绑定的dom元素
this.div = OpenLayers.Util.getElement(div);
if(!this.div) {
this.div = document.createElement("div");//没找到dom的创建一个, 宽高为1
this.div.style.height = "1px";
this.div.style.width = "1px";
}
OpenLayers.Element.addClass(this.div, 'olMap');
//viewpoint是div里最外层的
var id = this.id + "_OpenLayers_ViewPort";
this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
"relative", null,
"hidden");
this.viewPortDiv.style.width = "100%";
this.viewPortDiv.style.height = "100%";
this.viewPortDiv.className = "olMapViewport";
this.div.appendChild(this.viewPortDiv);//在map需要绑定的div里内层直接套viewport
//给this(新的map实例)绑定事件: 接收事件的对象是viewPort 监听事件暂时为空
this.events = new OpenLayers.Events(
this, this.viewPortDiv, null, this.fallThrough,
{includeXY: true}
);
//瓦片管理, 这个没看
if (OpenLayers.TileManager && this.tileManager !== null) {
if (!(this.tileManager instanceof OpenLayers.TileManager)) {
this.tileManager = new OpenLayers.TileManager(this.tileManager);
}
this.tileManager.addMap(this);
}
// 续写一个id, 根据此唯一id创建一个div
id = this.id + "_OpenLayers_Container";
this.layerContainerDiv = OpenLayers.Util.createDiv(id);
this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;//比气泡z-index少1
this.layerContainerOriginPx = {x: 0, y: 0};
this.applyTransform();
this.viewPortDiv.appendChild(this.layerContainerDiv);
this.updateSize();
//如果传入eventListeners对象的话, 就都on一下
if(this.eventListeners instanceof Object) {
this.events.on(this.eventListeners);
}
if (this.autoUpdateSize === true) {
// 如果autoUpdateSize配置为true的话, 增加一个窗口的'resize'事件的监听
this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,
this);
OpenLayers.Event.observe(window, 'resize',
this.updateSizeDestroy);
}
// 设置css风格的话
if(this.theme) {
// 检查是否已有相等的url
var addNode = true;
var nodes = document.getElementsByTagName('link');
for(var i=0, len=nodes.length; i<len; ++i) {
if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
this.theme)) {
addNode = false;
break;
}
}
// 需要把设置的风格url字串写入新的css外链元素, 而后去加载
if(addNode) {
var cssNode = document.createElement('link');
cssNode.setAttribute('rel', 'stylesheet');
cssNode.setAttribute('type', 'text/css');
cssNode.setAttribute('href', this.theme);
document.getElementsByTagName('head')[0].appendChild(cssNode);
}
}
//没传入控件, 默认的控件
if (this.controls == null) {
this.controls = [];
if (OpenLayers.Control != null) { //在此之前已经加载过OpenLayers.Control
//导航控件
if (OpenLayers.Control.Navigation) {
this.controls.push(new OpenLayers.Control.Navigation());
} else if (OpenLayers.Control.TouchNavigation) {
this.controls.push(new OpenLayers.Control.TouchNavigation());
}
//zoom控件
if (OpenLayers.Control.Zoom) {
this.controls.push(new OpenLayers.Control.Zoom());
} else if (OpenLayers.Control.PanZoom) {
this.controls.push(new OpenLayers.Control.PanZoom());
}
//url解析控件
if (OpenLayers.Control.ArgParser) {
this.controls.push(new OpenLayers.Control.ArgParser());
}
//给图层增加属性的控件
if (OpenLayers.Control.Attribution) {
this.controls.push(new OpenLayers.Control.Attribution());
}
}
}
//遍历控件添加到map
for(var i=0, len=this.controls.length; i<len; i++) {
this.addControlToMap(this.controls[i]);
}
this.popups = [];
//销毁事件
this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
// 窗口关闭时调用销毁事件
OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
// 初始化layers
if (options && options.layers) {
//运行顺序问题先删掉中心点和zoom
delete this.center;
delete this.zoom;
this.addLayers(options.layers);
//都添加完layers之后再set中心点+zoom
if (options.center && !this.getCenter()) {
this.setCenter(options.center, options.zoom);
}
}
//默认的移动和zoom方法
if (this.panMethod) {
this.panTween = new OpenLayers.Tween(this.panMethod);
}
if (this.zoomMethod && this.applyTransform.transform) {
this.zoomTween = new OpenLayers.Tween(this.zoomMethod);
}
},