OpenLayers学习8-Bounds(首个类)

Bounds边界, 这是第一次看OpenLayers类的代码, 好好体会了一下他怎么组织代码:

OpenLayers.Bounds在完成OpenLayers.Class()类的声明之后, OpenLayers.Bounds只是指向构造函数.
当new OpenLayers.Bounds()时, 产生一个实例, 此实例才是所需对象

实例构造时传入”左下右上”四个参数, 类中的全部方法以此”左下右上”为判断的基础,
实例方法纯完面向对象, 很少有js里面向过程的思想
类的静态方法写法类似:OpenLayers.Bounds.fromArray = function() {return …}, 补充完善OO.

一:类

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
/**
* Class: OpenLayers.Bounds
* Bounds边界,分别存储left, bottom, right, top, 初值是null
*
* 示例:
* (code)
* bounds = new OpenLayers.Bounds();
* bounds.extend(new OpenLayers.LonLat(4,5));
* bounds.extend(new OpenLayers.LonLat(5,6));
* bounds.toBBOX(); // returns 4,5,5,6
* (end)
*/
OpenLayers.Bounds = OpenLayers.Class({
//左下右上,边界值
left: null,
bottom: null,
right: null,
top: null,
//中心点lonlat, (OpenLayers.LonLat型)
centerLonLat: null,
//构造函数, 把四至存储到new出来的对象里
//这块没有类似left必须必right小 这一类的预防性判断
initialize: function(left, bottom, right, top) {
//传入数组的话, 就是[左,下,右,上]
if (OpenLayers.Util.isArray(left)) {
top = left[3];
right = left[2];
bottom = left[1];
left = left[0];
}
//传参统一toFloat
if (left != null) {
this.left = OpenLayers.Util.toFloat(left);
}
if (bottom != null) {
this.bottom = OpenLayers.Util.toFloat(bottom);
}
if (right != null) {
this.right = OpenLayers.Util.toFloat(right);
}
if (top != null) {
this.top = OpenLayers.Util.toFloat(top);
}
},
//生成个新的OpenLayers.Bounds实例, 拷贝现有参数
clone:function() {
//此时的OpenLayers.Bounds其实就指向声明的构造函数
return new OpenLayers.Bounds(this.left, this.bottom,
this.right, this.top);
},
//判断是否全等
equals:function(bounds) {
var equals = false;
if (bounds != null) {
equals = ((this.left == bounds.left) &&
(this.right == bounds.right) &&
(this.top == bounds.top) &&
(this.bottom == bounds.bottom));
}
return equals;
},
//返回字串: "左,下,右,上"
toString:function() {
return [this.left, this.bottom, this.right, this.top].join(",");
},
//返回数组, AxisOrder为true的话 顺序有变化
toArray: function(reverseAxisOrder) {
if (reverseAxisOrder === true) {
return [this.bottom, this.left, this.top, this.right];
} else {
return [this.left, this.bottom, this.right, this.top];
}
},
//返回字串, 边界经过修正( 小数有效位, 四舍五入等 )
toBBOX:function(decimal, reverseAxisOrder) {
if (decimal== null) {
decimal = 6;//小数点后有效位数
}
var mult = Math.pow(10, decimal);//10的decimal次方
var xmin = Math.round(this.left * mult) / mult;//四舍五入, 保留decimal个小数位
var ymin = Math.round(this.bottom * mult) / mult;
var xmax = Math.round(this.right * mult) / mult;
var ymax = Math.round(this.top * mult) / mult;
if (reverseAxisOrder === true) {
return ymin + "," + xmin + "," + ymax + "," + xmax;
} else {
return xmin + "," + ymin + "," + xmax + "," + ymax;
}
},
//把边界转化成 OpenLayers.Geometry.Polygon
toGeometry: function() {
return new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(this.left, this.bottom),
new OpenLayers.Geometry.Point(this.right, this.bottom),
new OpenLayers.Geometry.Point(this.right, this.top),
new OpenLayers.Geometry.Point(this.left, this.top)
])
]);
},
//宽度: 右减左
getWidth:function() {
return (this.right - this.left);
},
//高度: 上减下
getHeight:function() {
return (this.top - this.bottom);
},
//把宽高转化成OpenLayers.Size
getSize:function() {
return new OpenLayers.Size(this.getWidth(), this.getHeight());
},
//把宽高转成OpenLayers.Pixel
getCenterPixel:function() {
return new OpenLayers.Pixel( (this.left + this.right) / 2,
(this.bottom + this.top) / 2);
},
//当前位置除以2 获得中心点, 返回OpenLayers.LonLat
getCenterLonLat:function() {
if(!this.centerLonLat) {
this.centerLonLat = new OpenLayers.LonLat(
(this.left + this.right) / 2, (this.bottom + this.top) / 2
);
}
return this.centerLonLat;
},
//通过新ratio计算新的对应的Bounds
scale: function(ratio, origin){
if(origin == null){
origin = this.getCenterLonLat();//中心点
}
var origx,origy;//中心点xy坐标
if(origin.CLASS_NAME == "OpenLayers.LonLat"){//判断类名CLASS_NAME
origx = origin.lon;
origy = origin.lat;
} else {
origx = origin.x;
origy = origin.y;
}
var left = (this.left - origx) * ratio + origx;//新的边界计算, 算法没看明白, 回头再想
var bottom = (this.bottom - origy) * ratio + origy;
var right = (this.right - origx) * ratio + origx;
var top = (this.top - origy) * ratio + origy;
return new OpenLayers.Bounds(left, bottom, right, top);
},
//计算扩展后的Bounds, 当前边界加上x(或y), 返回新Bounds
add:function(x, y) {
if ( (x == null) || (y == null) ) {
throw new TypeError('Bounds.add cannot receive null values');
}
return new OpenLayers.Bounds(this.left + x, this.bottom + y,
this.right + x, this.top + y);
},
//扩展当前的的Bounds对象, 统一处理传入的LonLat/Point/Bounds
extend:function(object) {
if (object) {
switch(object.CLASS_NAME) {
case "OpenLayers.LonLat":
this.extendXY(object.lon, object.lat);
break;
case "OpenLayers.Geometry.Point":
this.extendXY(object.x, object.y);
break;
case "OpenLayers.Bounds":
//清空中心点 但当前不
this.centerLonLat = null;
if ( (this.left == null) || (object.left < this.left)) {
this.left = object.left;
}
if ( (this.bottom == null) || (object.bottom < this.bottom) ) {
this.bottom = object.bottom;
}
if ( (this.right == null) || (object.right > this.right) ) {
this.right = object.right;
}
if ( (this.top == null) || (object.top > this.top) ) {
this.top = object.top;
}
break;
}
}
},
//以xy扩展本对象内的边界
extendXY:function(x, y) {
//清空缓存的中心点经纬度
this.centerLonLat = null;
if ((this.left == null) || (x < this.left)) {
this.left = x;
}
if ((this.bottom == null) || (y < this.bottom)) {
this.bottom = y;
}
if ((this.right == null) || (x > this.right)) {
this.right = x;
}
if ((this.top == null) || (y > this.top)) {
this.top = y;
}
},
//判断本对象内, 是否包含传入的LonLat(ll), worldBounds
//options可以包含inclusive:是否包含边界, worldBounds:没太看懂, 包含在世界边界内, 还和换日线有关...
containsLonLat: function(ll, options) {
if (typeof options === "boolean") {
options = {inclusive: options};
}
options = options || {};
//用contains方法判断是否包含在其中
var contains = this.contains(ll.lon, ll.lat, options.inclusive),
worldBounds = options.worldBounds;
//有worldBounds选项 且 之前判断不包含
if (worldBounds && !contains) {
var worldWidth = worldBounds.getWidth();
var worldCenterX = (worldBounds.left + worldBounds.right) / 2;
var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth);//不理解这个worldsAway干吗的
//根据worldsAway再判断一次
contains = this.containsLonLat({
lon: ll.lon - worldsAway * worldWidth,
lat: ll.lat
}, {inclusive: options.inclusive});
}
return contains;
},
//contains适配一层, px是Pixel对象.
//inclusive为是否包含边界
containsPixel:function(px, inclusive) {
return this.contains(px.x, px.y, inclusive);
},
//是否包含, 核心判断方法
contains:function(x, y, inclusive) {
//默认为true
if (inclusive == null) {
inclusive = true;
}
if (x == null || y == null) {
return false;
}
x = OpenLayers.Util.toFloat(x);
y = OpenLayers.Util.toFloat(y);
var contains = false;
if (inclusive) {
//包含边界的话就多了个"等于"
contains = ((x >= this.left) && (x = this.bottom) && (y this.left) && (x < this.right) &&
(y > this.bottom) && (y < this.top));
}
return contains;
},
//判断给定的边界是否从本对象中穿过(intersect),或互相包含
//options还是inclusive和worldBounds两项
intersectsBounds:function(bounds, options) {
if (typeof options === "boolean") {
options = {inclusive: options};
}
options = options || {};
if (options.worldBounds) {
var self = this.wrapDateLine(options.worldBounds);
bounds = bounds.wrapDateLine(options.worldBounds);
} else {
self = this;
}
if (options.inclusive == null) {
options.inclusive = true;
}
var intersects = false;
var mightTouch = (
self.left == bounds.right ||
self.right == bounds.left ||
self.top == bounds.bottom ||
self.bottom == bounds.top
);
// if the two bounds only touch at an edge, and inclusive is false,
// then the bounds don't *really* intersect.
if (options.inclusive || !mightTouch) {
// otherwise, if one of the boundaries even partially contains another,
// inclusive of the edges, then they do intersect.
var inBottom = (
((bounds.bottom >= self.bottom) && (bounds.bottom = bounds.bottom) && (self.bottom = self.bottom) && (bounds.top bounds.bottom) && (self.top < bounds.top))
);
var inLeft = (
((bounds.left >= self.left) && (bounds.left = bounds.left) && (self.left = self.left) && (bounds.right = bounds.left) && (self.right <= bounds.right))
);
intersects = ((inBottom || inTop) && (inLeft || inRight));
}
// document me
if (options.worldBounds && !intersects) {
var world = options.worldBounds;
var width = world.getWidth();
var selfCrosses = !world.containsBounds(self);
var boundsCrosses = !world.containsBounds(bounds);
if (selfCrosses && !boundsCrosses) {
bounds = bounds.add(-width, 0);
intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive});
} else if (boundsCrosses && !selfCrosses) {
self = self.add(-width, 0);
intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive});
}
}
return intersects;
},
//本对象是否包含给传入的Bounds
containsBounds:function(bounds, partial, inclusive) {
if (partial == null) {
partial = false;
}
if (inclusive == null) {
inclusive = true;
}
var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive);
var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
var topLeft = this.contains(bounds.left, bounds.top, inclusive);
var topRight = this.contains(bounds.right, bounds.top, inclusive);
return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
: (bottomLeft && bottomRight && topLeft && topRight);
},
// 返回给定lonlat在本对象内所属的象限(四象限"br", "tr", "tl", "bl")
determineQuadrant: function(lonlat) {
var quadrant = "";
var center = this.getCenterLonLat();
quadrant += (lonlat.lat < center.lat) ? "b" : "t";
quadrant += (lonlat.lon < center.lon) ? "l" : "r";
return quadrant;
},
// 把Bounds从原投影类型转换到目标投影类型
transform: function(source, dest) {
//清除中心点缓存
this.centerLonLat = null;
var ll = OpenLayers.Projection.transform(
{'x': this.left, 'y': this.bottom}, source, dest);
var lr = OpenLayers.Projection.transform(
{'x': this.right, 'y': this.bottom}, source, dest);
var ul = OpenLayers.Projection.transform(
{'x': this.left, 'y': this.top}, source, dest);
var ur = OpenLayers.Projection.transform(
{'x': this.right, 'y': this.top}, source, dest);
this.left = Math.min(ll.x, ul.x);
this.bottom = Math.min(ll.y, lr.y);
this.right = Math.max(lr.x, ur.x);
this.top = Math.max(ul.y, ur.y);
return this;
},
//通过对换日线的计算, 让Bounds实例能左右连续
//Options为leftTolerance和rightTolerance
wrapDateLine: function(maxExtent, options) {
options = options || {};
var leftTolerance = options.leftTolerance || 0;
var rightTolerance = options.rightTolerance || 0;
var newBounds = this.clone();
if (maxExtent) {
var width = maxExtent.getWidth();
//右移
while (newBounds.left < maxExtent.left &&
newBounds.right - rightTolerance = maxExtent.right &&
newBounds.right > maxExtent.right ) {
newBounds = newBounds.add(-width, 0);
}
// crosses right only? force left, 仅穿过右边, 强制向左 没看懂...
var newLeft = newBounds.left + leftTolerance;
if (newLeft < maxExtent.right && newLeft > maxExtent.left &&
newBounds.right - rightTolerance > maxExtent.right) {
newBounds = newBounds.add(-width, 0);
}
}
return newBounds;
},
//类名, 需要判断传参是某种实例的时候特别有用
CLASS_NAME: "OpenLayers.Bounds"
});

二: 静态方法

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
//以下是OpenLayers.Bounds类的静态方法
//str是"左,下,右,上",reverseAxisOrder是是否使用reverseAxis顺序
OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
var bounds = str.split(",");
return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
};
//bbox是[左,下,右,上]
OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
return reverseAxisOrder === true ?
new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) :
new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]);
};
//从OpenLayers.Size构造 Bounds(0,h,w,0)
OpenLayers.Bounds.fromSize = function(size) {
return new OpenLayers.Bounds(0,
size.h,
size.w,
0);
};
// 相反的象限, 如和"bl"相对的就是"tr"
OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
var opp = "";
opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
return opp;
};