OpenLayers源码学习18:图层Layer.Grid_2

然后grid的第二部分

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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
// 调整背景缓存(back buffer),
applyBackBuffer: function(resolution) {
if(this.backBufferTimerId !== null) {
this.removeBackBuffer();
}
var backBuffer = this.backBuffer;
if(!backBuffer) {
backBuffer = this.createBackBuffer();
if(!backBuffer) {
return;
}
if (resolution === this.gridResolution) {
//分辨率相等
this.div.insertBefore(backBuffer, this.div.firstChild);//将backbuffer插到div最前边
} else {
//分辨率不等的话, 插到baseLayer前边
this.map.baseLayer.div.parentNode.insertBefore(backBuffer, this.map.baseLayer.div);
}
this.backBuffer = backBuffer;
// 缓存第一张瓦片的left/top
var topLeftTileBounds = this.grid[0][0].bounds;
this.backBufferLonLat = {
lon: topLeftTileBounds.left,
lat: topLeftTileBounds.top
};
this.backBufferResolution = this.gridResolution;
}
var ratio = this.backBufferResolution / resolution;
// 调整backBuffer里所有瓦片的偏移
var tiles = backBuffer.childNodes, tile;
for (var i=tiles.length-1; i>=0; --i) {
tile = tiles[i];
tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px';
tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px';
tile.style.width = Math.round(ratio * tile._w) + 'px';
tile.style.height = Math.round(ratio * tile._h) + 'px';
}
// 调整backBuffer的位置
var position = this.getViewPortPxFromLonLat(
this.backBufferLonLat, resolution);
var leftOffset = this.map.layerContainerOriginPx.x;
var topOffset = this.map.layerContainerOriginPx.y;
backBuffer.style.left = Math.round(position.x - leftOffset) + 'px';
backBuffer.style.top = Math.round(position.y - topOffset) + 'px';
},
// 创建背景画布
createBackBuffer: function() {
var backBuffer;
if(this.grid.length > 0) {
backBuffer = document.createElement('div');
backBuffer.id = this.div.id + '_bb';//backBuffer
backBuffer.className = 'olBackBuffer';
backBuffer.style.position = 'absolute';
var map = this.map;
backBuffer.style.zIndex = this.transitionEffect === 'resize' ?
this.getZIndex() - 1 :
// 'map-resize':
map.Z_INDEX_BASE.BaseLayer -
(map.getNumLayers() - map.getLayerIndex(this));//各种情况的z-index
for(var i=0, lenI=this.grid.length; i<lenI; i++) {
for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) {
var tile = this.grid[i][j],
markup = this.grid[i][j].createBackBuffer();//瓦片的createBackBuffer
if (markup) {
markup._i = i;//单张瓦片的各个属性
markup._j = j;
markup._w = tile.size.w;
markup._h = tile.size.h;
markup.id = tile.id + '_bb';
backBuffer.appendChild(markup);
}
}
}
}
return backBuffer;
},
// 从dom里删除bb
removeBackBuffer: function() {
if (this._transitionElement) {//不知道这个是什么变换
for (var i=this.transitionendEvents.length-1; i>=0; --i) {
OpenLayers.Event.stopObserving(this._transitionElement,
this.transitionendEvents[i], this._removeBackBuffer);
}
delete this._transitionElement;
}
if(this.backBuffer) {
if (this.backBuffer.parentNode) {
this.backBuffer.parentNode.removeChild(this.backBuffer);//删除dom
}
this.backBuffer = null;
this.backBufferResolution = null;
if(this.backBufferTimerId !== null) {
window.clearTimeout(this.backBufferTimerId);//timer也得清掉
this.backBufferTimerId = null;
}
}
},
// 移动图层
moveByPx: function(dx, dy) {
if (!this.singleTile) {
this.moveGriddedTiles();
}
},
setTileSize: function(size) {
if (this.singleTile) {
size = this.map.getSize();
size.h = parseInt(size.h * this.ratio, 10);
size.w = parseInt(size.w * this.ratio, 10);
}
OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this, [size]);
},
// 获得瓦片边界
getTilesBounds: function() {
var bounds = null;
var length = this.grid.length;
if (length) {
var bottomLeftTileBounds = this.grid[length - 1][0].bounds,//角落的bounds
width = this.grid[0].length * bottomLeftTileBounds.getWidth(),//行的瓦片数
height = this.grid.length * bottomLeftTileBounds.getHeight();//列内瓦片数
bounds = new OpenLayers.Bounds(bottomLeftTileBounds.left,
bottomLeftTileBounds.bottom,
bottomLeftTileBounds.left + width,
bottomLeftTileBounds.bottom + height);//最大值
}
return bounds;
},
//初始化单瓦片模式
initSingleTile: function(bounds) {
//触发事件
this.events.triggerEvent("retile");
//创建新的bound
var center = bounds.getCenterLonLat();
var tileWidth = bounds.getWidth() * this.ratio;
var tileHeight = bounds.getHeight() * this.ratio;
var tileBounds =
new OpenLayers.Bounds(center.lon - (tileWidth/2),
center.lat - (tileHeight/2),
center.lon + (tileWidth/2),
center.lat + (tileHeight/2));//从中心点计算瓦片边界
//转换到像素坐标
var px = this.map.getLayerPxFromLonLat({
lon: tileBounds.left,
lat: tileBounds.top
});
if (!this.grid.length) {
this.grid[0] = [];
}
var tile = this.grid[0][0];//第一张
if (!tile) {
tile = this.addTile(tileBounds, px);//添加瓦片
this.addTileMonitoringHooks(tile);
tile.draw();//绘制瓦片
this.grid[0][0] = tile;
} else {
tile.moveTo(tileBounds, px);//之前有就移动瓦片
}
//remove all but our single tile
this.removeExcessTiles(1,1);
// 缓存分辨率
this.gridResolution = this.getServerResolution();
},
// 计算grid的布局
calculateGridLayout: function(bounds, origin, resolution) {
//单张瓦片对应的经纬跨度
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
//经度 全局偏移
var offsetlon = bounds.left - origin.lon;
//行号
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
//
var rowSign = this.rowSign;
//纬度 全局偏移
var offsetlat = rowSign * (origin.lat - bounds.top + tilelat);
//列号
var tilerow = Math[~rowSign ? 'floor' : 'ceil'](offsetlat/tilelat) - this.buffer * rowSign;
return {
tilelon: tilelon, tilelat: tilelat,
startcol: tilecol, startrow: tilerow
};
},
// 获得瓦片的原始位置
getTileOrigin: function() {
var origin = this.tileOrigin;
if (!origin) {
var extent = this.getMaxExtent();
var edges = ({
"tl": ["left", "top"],
"tr": ["right", "top"],
"bl": ["left", "bottom"],
"br": ["right", "bottom"]
})[this.tileOriginCorner];
origin = new OpenLayers.LonLat(extent[edges[0]], extent[edges[1]]);
}
return origin;
},
// 根据行列号去计算瓦片的bounds
getTileBoundsForGridIndex: function(row, col) {
var origin = this.getTileOrigin();
var tileLayout = this.gridLayout;
var tilelon = tileLayout.tilelon;
var tilelat = tileLayout.tilelat;
var startcol = tileLayout.startcol;
var startrow = tileLayout.startrow;
var rowSign = this.rowSign;
return new OpenLayers.Bounds(
origin.lon + (startcol + col) * tilelon,//原始经度 + 行号x瓦片经度
origin.lat - (startrow + row * rowSign) * tilelat * rowSign,
origin.lon + (startcol + col + 1) * tilelon,
origin.lat - (startrow + (row - 1) * rowSign) * tilelat * rowSign
);
},
// 初始化排列好的瓦片
initGriddedTiles:function(bounds) {
this.events.triggerEvent("retile");
//size
var viewSize = this.map.getSize();
//瓦片原点
var origin = this.getTileOrigin();
var resolution = this.map.getResolution(),
serverResolution = this.getServerResolution(),
ratio = resolution / serverResolution,
tileSize = {
w: this.tileSize.w / ratio,
h: this.tileSize.h / ratio
};
//最小行列号
var minRows = Math.ceil(viewSize.h/tileSize.h) +
2 * this.buffer + 1;
var minCols = Math.ceil(viewSize.w/tileSize.w) +
2 * this.buffer + 1;
var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
this.gridLayout = tileLayout;
var tilelon = tileLayout.tilelon;
var tilelat = tileLayout.tilelat;
//图层容器的原始坐标
var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
var layerContainerDivTop = this.map.layerContainerOriginPx.y;
var tileBounds = this.getTileBoundsForGridIndex(0, 0);
var startPx = this.map.getViewPortPxFromLonLat(
new OpenLayers.LonLat(tileBounds.left, tileBounds.top)
);
//计算起始px
startPx.x = Math.round(startPx.x) - layerContainerDivLeft;
startPx.y = Math.round(startPx.y) - layerContainerDivTop;
var tileData = [], center = this.map.getCenter();
var rowidx = 0;
do {
var row = this.grid[rowidx];
if (!row) {//新的一行
row = [];
this.grid.push(row);
}
var colidx = 0;
do {
tileBounds = this.getTileBoundsForGridIndex(rowidx, colidx);
var px = startPx.clone();
px.x = px.x + colidx * Math.round(tileSize.w);//像素偏移
px.y = px.y + rowidx * Math.round(tileSize.h);
var tile = row[colidx];
if (!tile) {//此位置上没瓦片就得新建一个
tile = this.addTile(tileBounds, px);
this.addTileMonitoringHooks(tile);
row.push(tile);
} else {
//原先就有的话, 移动到指定位置
tile.moveTo(tileBounds, px, false);
}
var tileCenter = tileBounds.getCenterLonLat();
tileData.push({
tile: tile,
distance: Math.pow(tileCenter.lon - center.lon, 2) +
Math.pow(tileCenter.lat - center.lat, 2)//缓存距离
});
colidx += 1;
} while ((tileBounds.right <= bounds.right + tilelon * this.buffer)//超过距离 或 超过编号就结束
|| colidx < minCols);
rowidx += 1;
} while((tileBounds.bottom >= bounds.bottom - tilelat * this.buffer)
|| rowidx < minRows);//超过距离 或 超过编号结束
//去掉已经不用的瓦片
this.removeExcessTiles(rowidx, colidx);
var resolution = this.getServerResolution();
// 缓存grid的分辨率
this.gridResolution = resolution;
//给缓存tileData排序, 准备绘制
tileData.sort(function(a, b) {
return a.distance - b.distance;
});
//重绘瓦片
for (var i=0, ii=tileData.length; i<ii; ++i) {
tileData[i].tile.draw();
}
},
getMaxExtent: function() {
return this.maxExtent;
},
// 添加瓦片, 调用事件
addTile: function(bounds, position) {
var tile = new this.tileClass(
this, position, bounds, null, this.tileSize, this.tileOptions
);
this.events.triggerEvent("addtile", {tile: tile});
return tile;
},
// 添加瓦片的回调钩子
addTileMonitoringHooks: function(tile) {
var replacingCls = 'olTileReplacing';
tile.onLoadStart = function() {
//首次加载
if (this.loading === false) {
this.loading = true;
this.events.triggerEvent("loadstart");
}
this.events.triggerEvent("tileloadstart", {tile: tile});
this.numLoadingTiles++;//正在加载计数器
if (!this.singleTile && this.backBuffer && this.gridResolution === this.backBufferResolution) {
OpenLayers.Element.addClass(tile.getTile(), replacingCls);
}
};
tile.onLoadEnd = function(evt) {
this.numLoadingTiles--;//计数器递减
var aborted = evt.type === 'unload';
this.events.triggerEvent("tileloaded", {
tile: tile,
aborted: aborted
});
if (!this.singleTile && !aborted && this.backBuffer && this.gridResolution === this.backBufferResolution) {
var tileDiv = tile.getTile();
if (OpenLayers.Element.getStyle(tileDiv, 'display') === 'none') {
var bufferTile = document.getElementById(tile.id + '_bb');
if (bufferTile) {
bufferTile.parentNode.removeChild(bufferTile);
}
}
OpenLayers.Element.removeClass(tileDiv, replacingCls);
}
//全都加载完了
if (this.numLoadingTiles === 0) {
if (this.backBuffer) {
if (this.backBuffer.childNodes.length === 0) {
// bb没用了 删掉
this.removeBackBuffer();
} else {
// 对动画的操作
this._transitionElement = aborted ?
this.div.lastChild : tile.imgDiv;
var transitionendEvents = this.transitionendEvents;
for (var i=transitionendEvents.length-1; i>=0; --i) {
OpenLayers.Event.observe(this._transitionElement,
transitionendEvents[i],
this._removeBackBuffer);
}
// 增加延迟
this.backBufferTimerId = window.setTimeout(
this._removeBackBuffer, this.removeBackBufferDelay
);
}
}
this.loading = false;
this.events.triggerEvent("loadend");
}
};
tile.onLoadError = function() {
this.events.triggerEvent("tileerror", {tile: tile});
};
//初始化瓦片事件
tile.events.on({
"loadstart": tile.onLoadStart,
"loadend": tile.onLoadEnd,
"unload": tile.onLoadEnd,
"loaderror": tile.onLoadError,
scope: this
});
},
// 解绑瓦片事件
removeTileMonitoringHooks: function(tile) {
tile.unload();
tile.events.un({
"loadstart": tile.onLoadStart,
"loadend": tile.onLoadEnd,
"unload": tile.onLoadEnd,
"loaderror": tile.onLoadError,
scope: this
});
},
// 移动组织好的瓦片
moveGriddedTiles: function() {
var buffer = this.buffer + 1;
while(true) {
var tlTile = this.grid[0][0];//top-left的瓦片
var tlViewPort = {
x: tlTile.position.x +
this.map.layerContainerOriginPx.x,//计算左上角view port的x值
y: tlTile.position.y +
this.map.layerContainerOriginPx.y
};
var ratio = this.getServerResolution() / this.map.getResolution();
var tileSize = {
w: Math.round(this.tileSize.w * ratio),//根据比率放大后的瓦片尺寸
h: Math.round(this.tileSize.h * ratio)
};
//判断是横向 还是纵向移动
if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
this.shiftColumn(true, tileSize);
} else if (tlViewPort.x < -tileSize.w * buffer) {
this.shiftColumn(false, tileSize);
} else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
this.shiftRow(true, tileSize);
} else if (tlViewPort.y < -tileSize.h * buffer) {
this.shiftRow(false, tileSize);
} else {
break;
}
}
},
//移动行
//prepend为真, 就是从0行开始 / 否则就是末行
shiftRow: function(prepend, tileSize) {
var grid = this.grid;
var rowIndex = prepend ? 0 : (grid.length - 1);//首行 / 末行
var sign = prepend ? -1 : 1;//向左是-1 , 向右是1
var rowSign = this.rowSign;
var tileLayout = this.gridLayout;
tileLayout.startrow += sign * rowSign;//向左 / 向右移动
var modelRow = grid[rowIndex];//共多少行
var row = grid[prepend ? 'pop' : 'shift']();
for (var i=0, len=row.length; i<len; i++) {
var tile = row[i];
var position = modelRow[i].position.clone();
position.y += tileSize.h * sign;//y轴 偏移量
tile.moveTo(this.getTileBoundsForGridIndex(rowIndex, i), position);//y轴移动距离
}
grid[prepend ? 'unshift' : 'push'](row);//调用grid[1/-1]
},
//移动列
shiftColumn: function(prepend, tileSize) {
var grid = this.grid;
var colIndex = prepend ? 0 : (grid[0].length - 1);//true是第一列, false是末一列
var sign = prepend ? -1 : 1;
var tileLayout = this.gridLayout;
tileLayout.startcol += sign;
for (var i=0, len=grid.length; i<len; i++) {
var row = grid[i];
var position = row[colIndex].position.clone();
var tile = row[prepend ? 'pop' : 'shift']();
position.x += tileSize.w * sign;
tile.moveTo(this.getTileBoundsForGridIndex(i, colIndex), position);//列移动
row[prepend ? 'unshift' : 'push'](tile);
}
},
//删掉多余瓦片
removeExcessTiles: function(rows, columns) {
var i, l;
//传入的r和l是保留的最大行列号
while (this.grid.length > rows) {
var row = this.grid.pop();
for (i=0, l=row.length; i<l; i++) {
var tile = row[i];
this.destroyTile(tile);
}
}
for (i=0, l=this.grid.length; i<l; i++) {
while (this.grid[i].length > columns) {
var row = this.grid[i];
var tile = row.pop();
this.destroyTile(tile);
}
}
},
// 单瓦片模式需要调整
onMapResize: function() {
if (this.singleTile) {
this.clearGrid();
this.setTileSize();
}
},
//获得瓦片边界
getTileBounds: function(viewPortPx) {
var maxExtent = this.maxExtent;
var resolution = this.getResolution();
var tileMapWidth = resolution * this.tileSize.w;
var tileMapHeight = resolution * this.tileSize.h;
var mapPoint = this.getLonLatFromViewPortPx(viewPortPx);//viewport的像素位置
var tileLeft = maxExtent.left + (tileMapWidth *
Math.floor((mapPoint.lon -
maxExtent.left) /
tileMapWidth));
var tileBottom = maxExtent.bottom + (tileMapHeight *
Math.floor((mapPoint.lat -
maxExtent.bottom) /
tileMapHeight));
return new OpenLayers.Bounds(tileLeft, tileBottom,
tileLeft + tileMapWidth,
tileBottom + tileMapHeight);
},
CLASS_NAME: "OpenLayers.Layer.Grid"
});