1
/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2
* license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3
* full text of the license. */
6
* Class: OpenLayers.Bounds
7
* Instances of this class represent bounding boxes. Data stored as left,
8
* bottom, right, top floats. All values are initialized to null, however,
9
* you should make sure you set them before using the bounds for anything.
12
* > bounds = new OpenLayers.Bounds();
13
* > bounds.extend(new OpenLayers.LonLat(4,5));
14
* > bounds.extend(new OpenLayers.LonLat(5,6));
15
* > bounds.toBBOX(); // returns 4,5,5,6
17
OpenLayers.Bounds = OpenLayers.Class({
21
* {Number} Minimum horizontal coordinate.
27
* {Number} Minimum vertical coordinate.
33
* {Number} Maximum horizontal coordinate.
39
* {Number} Maximum vertical coordinate.
44
* Property: centerLonLat
45
* {<OpenLayers.LonLat>} A cached center location. This should not be
46
* accessed directly. Use <getCenterLonLat> instead.
51
* Constructor: OpenLayers.Bounds
52
* Construct a new bounds object.
55
* left - {Number} The left bounds of the box. Note that for width
56
* calculations, this is assumed to be less than the right value.
57
* bottom - {Number} The bottom bounds of the box. Note that for height
58
* calculations, this is assumed to be more than the top value.
59
* right - {Number} The right bounds.
60
* top - {Number} The top bounds.
62
initialize: function(left, bottom, right, top) {
64
this.left = parseFloat(left);
67
this.bottom = parseFloat(bottom);
70
this.right = parseFloat(right);
73
this.top = parseFloat(top);
79
* Create a cloned instance of this bounds.
82
* {<OpenLayers.Bounds>} A fresh copy of the bounds
85
return new OpenLayers.Bounds(this.left, this.bottom,
86
this.right, this.top);
91
* Test a two bounds for equivalence.
94
* bounds - {<OpenLayers.Bounds>}
97
* {Boolean} The passed-in bounds object has the same left,
98
* right, top, bottom components as this. Note that if bounds
99
* passed in is null, returns false.
101
equals:function(bounds) {
103
if (bounds != null) {
104
equals = ((this.left == bounds.left) &&
105
(this.right == bounds.right) &&
106
(this.top == bounds.top) &&
107
(this.bottom == bounds.bottom));
113
* APIMethod: toString
116
* {String} String representation of bounds object.
117
* (ex.<i>"left-bottom=(5,42) right-top=(10,45)"</i>)
119
toString:function() {
120
return ( "left-bottom=(" + this.left + "," + this.bottom + ")"
121
+ " right-top=(" + this.right + "," + this.top + ")" );
128
* {Array} array of left, bottom, right, top
130
toArray: function() {
131
return [this.left, this.bottom, this.right, this.top];
138
* decimal - {Integer} How many significant digits in the bbox coords?
142
* {String} Simple String representation of bounds object.
143
* (ex. <i>"5,42,10,45"</i>)
145
toBBOX:function(decimal) {
146
if (decimal== null) {
149
var mult = Math.pow(10, decimal);
150
var bbox = Math.round(this.left * mult) / mult + "," +
151
Math.round(this.bottom * mult) / mult + "," +
152
Math.round(this.right * mult) / mult + "," +
153
Math.round(this.top * mult) / mult;
159
* APIMethod: toGeometry
160
* Create a new polygon geometry based on this bounds.
163
* {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
166
toGeometry: function() {
167
return new OpenLayers.Geometry.Polygon([
168
new OpenLayers.Geometry.LinearRing([
169
new OpenLayers.Geometry.Point(this.left, this.bottom),
170
new OpenLayers.Geometry.Point(this.right, this.bottom),
171
new OpenLayers.Geometry.Point(this.right, this.top),
172
new OpenLayers.Geometry.Point(this.left, this.top)
178
* APIMethod: getWidth
181
* {Float} The width of the bounds
183
getWidth:function() {
184
return (this.right - this.left);
188
* APIMethod: getHeight
191
* {Float} The height of the bounds (top minus bottom).
193
getHeight:function() {
194
return (this.top - this.bottom);
201
* {<OpenLayers.Size>} The size of the box.
204
return new OpenLayers.Size(this.getWidth(), this.getHeight());
208
* APIMethod: getCenterPixel
211
* {<OpenLayers.Pixel>} The center of the bounds in pixel space.
213
getCenterPixel:function() {
214
return new OpenLayers.Pixel( (this.left + this.right) / 2,
215
(this.bottom + this.top) / 2);
219
* APIMethod: getCenterLonLat
222
* {<OpenLayers.LonLat>} The center of the bounds in map space.
224
getCenterLonLat:function() {
225
if(!this.centerLonLat) {
226
this.centerLonLat = new OpenLayers.LonLat(
227
(this.left + this.right) / 2, (this.bottom + this.top) / 2
230
return this.centerLonLat;
235
* Scales the bounds around a pixel or lonlat. Note that the new
236
* bounds may return non-integer properties, even if a pixel
241
* origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
245
* {<OpenLayers.Bound>} A new bounds that is scaled by ratio
249
scale: function(ratio, origin){
251
origin = this.getCenterLonLat();
258
// get origin coordinates
259
if(origin.CLASS_NAME == "OpenLayers.LonLat"){
267
var left = (this.left - origx) * ratio + origx;
268
var bottom = (this.bottom - origy) * ratio + origy;
269
var right = (this.right - origx) * ratio + origx;
270
var top = (this.top - origy) * ratio + origy;
272
return new OpenLayers.Bounds(left, bottom, right, top);
283
* {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
284
* this, but shifted by the passed-in x and y values.
287
if ( (x == null) || (y == null) ) {
288
var msg = OpenLayers.i18n("boundsAddError");
289
OpenLayers.Console.error(msg);
292
return new OpenLayers.Bounds(this.left + x, this.bottom + y,
293
this.right + x, this.top + y);
298
* Extend the bounds to include the point, lonlat, or bounds specified.
299
* Note, this function assumes that left < right and bottom < top.
302
* object - {Object} Can be LonLat, Point, or Bounds
304
extend:function(object) {
307
// clear cached center location
308
switch(object.CLASS_NAME) {
309
case "OpenLayers.LonLat":
310
bounds = new OpenLayers.Bounds(object.lon, object.lat,
311
object.lon, object.lat);
313
case "OpenLayers.Geometry.Point":
314
bounds = new OpenLayers.Bounds(object.x, object.y,
318
case "OpenLayers.Bounds":
324
this.centerLonLat = null;
325
if ( (this.left == null) || (bounds.left < this.left)) {
326
this.left = bounds.left;
328
if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
329
this.bottom = bounds.bottom;
331
if ( (this.right == null) || (bounds.right > this.right) ) {
332
this.right = bounds.right;
334
if ( (this.top == null) || (bounds.top > this.top) ) {
335
this.top = bounds.top;
342
* APIMethod: containsLonLat
345
* ll - {<OpenLayers.LonLat>}
346
* inclusive - {Boolean} Whether or not to include the border.
350
* {Boolean} The passed-in lonlat is within this bounds.
352
containsLonLat:function(ll, inclusive) {
353
return this.contains(ll.lon, ll.lat, inclusive);
357
* APIMethod: containsPixel
360
* px - {<OpenLayers.Pixel>}
361
* inclusive - {Boolean} Whether or not to include the border. Default is
365
* {Boolean} The passed-in pixel is within this bounds.
367
containsPixel:function(px, inclusive) {
368
return this.contains(px.x, px.y, inclusive);
372
* APIMethod: contains
377
* inclusive - {Boolean} Whether or not to include the border. Default is
381
* {Boolean} Whether or not the passed-in coordinates are within this
384
contains:function(x, y, inclusive) {
387
if (inclusive == null) {
391
var contains = false;
393
contains = ((x >= this.left) && (x <= this.right) &&
394
(y >= this.bottom) && (y <= this.top));
396
contains = ((x > this.left) && (x < this.right) &&
397
(y > this.bottom) && (y < this.top));
403
* APIMethod: intersectsBounds
406
* bounds - {<OpenLayers.Bounds>}
407
* inclusive - {Boolean} Whether or not to include the border. Default
411
* {Boolean} The passed-in OpenLayers.Bounds object intersects this bounds.
412
* Simple math just check if either contains the other, allowing for
415
intersectsBounds:function(bounds, inclusive) {
417
if (inclusive == null) {
420
var inBottom = (bounds.bottom == this.bottom && bounds.top == this.top) ?
421
true : (((bounds.bottom > this.bottom) && (bounds.bottom < this.top)) ||
422
((this.bottom > bounds.bottom) && (this.bottom < bounds.top)));
423
var inTop = (bounds.bottom == this.bottom && bounds.top == this.top) ?
424
true : (((bounds.top > this.bottom) && (bounds.top < this.top)) ||
425
((this.top > bounds.bottom) && (this.top < bounds.top)));
426
var inRight = (bounds.right == this.right && bounds.left == this.left) ?
427
true : (((bounds.right > this.left) && (bounds.right < this.right)) ||
428
((this.right > bounds.left) && (this.right < bounds.right)));
429
var inLeft = (bounds.right == this.right && bounds.left == this.left) ?
430
true : (((bounds.left > this.left) && (bounds.left < this.right)) ||
431
((this.left > bounds.left) && (this.left < bounds.right)));
433
return (this.containsBounds(bounds, true, inclusive) ||
434
bounds.containsBounds(this, true, inclusive) ||
435
((inTop || inBottom ) && (inLeft || inRight )));
439
* APIMethod: containsBounds
441
* bounds - {<OpenLayers.Bounds>}
442
* partial - {Boolean} If true, only part of passed-in bounds needs be
443
* within this bounds. If false, the entire passed-in bounds must be
444
* within. Default is false
445
* inclusive - {Boolean} Whether or not to include the border. Default is
449
* {Boolean} The passed-in bounds object is contained within this bounds.
451
containsBounds:function(bounds, partial, inclusive) {
454
if (partial == null) {
457
if (inclusive == null) {
467
inLeft = (bounds.left >= this.left) && (bounds.left <= this.right);
468
inTop = (bounds.top >= this.bottom) && (bounds.top <= this.top);
469
inRight= (bounds.right >= this.left) && (bounds.right <= this.right);
470
inBottom = (bounds.bottom >= this.bottom) && (bounds.bottom <= this.top);
472
inLeft = (bounds.left > this.left) && (bounds.left < this.right);
473
inTop = (bounds.top > this.bottom) && (bounds.top < this.top);
474
inRight= (bounds.right > this.left) && (bounds.right < this.right);
475
inBottom = (bounds.bottom > this.bottom) && (bounds.bottom < this.top);
478
return (partial) ? (inTop || inBottom ) && (inLeft || inRight )
479
: (inTop && inLeft && inBottom && inRight);
483
* APIMethod: determineQuadrant
486
* lonlat - {<OpenLayers.LonLat>}
489
* {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
492
determineQuadrant: function(lonlat) {
495
var center = this.getCenterLonLat();
497
quadrant += (lonlat.lat < center.lat) ? "b" : "t";
498
quadrant += (lonlat.lon < center.lon) ? "l" : "r";
504
* APIMethod: transform
505
* Transform the Bounds object from source to dest.
508
* source - {<OpenLayers.Projection>} Source projection.
509
* dest - {<OpenLayers.Projection>} Destination projection.
512
* {<OpenLayers.Bounds>} Itself, for use in chaining operations.
514
transform: function(source, dest) {
515
// clear cached center location
516
this.centerLonLat = null;
517
var ll = OpenLayers.Projection.transform(
518
{'x': this.left, 'y': this.bottom}, source, dest);
519
var lr = OpenLayers.Projection.transform(
520
{'x': this.right, 'y': this.bottom}, source, dest);
521
var ul = OpenLayers.Projection.transform(
522
{'x': this.left, 'y': this.top}, source, dest);
523
var ur = OpenLayers.Projection.transform(
524
{'x': this.right, 'y': this.top}, source, dest);
525
this.left = Math.min(ll.x, ul.x);
526
this.bottom = Math.min(ll.y, lr.y);
527
this.right = Math.max(lr.x, ur.x);
528
this.top = Math.max(ul.y, ur.y);
533
* APIMethod: wrapDateLine
536
* maxExtent - {<OpenLayers.Bounds>}
537
* options - {Object} Some possible options are:
538
* leftTolerance - {float} Allow for a margin of error
539
* with the 'left' value of this
542
* rightTolerance - {float} Allow for a margin of error
543
* with the 'right' value of
548
* {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the
549
* "dateline" (as specified by the borders of
550
* maxExtent). Note that this function only returns
551
* a different bounds value if this bounds is
552
* *entirely* outside of the maxExtent. If this
553
* bounds straddles the dateline (is part in/part
554
* out of maxExtent), the returned bounds will be
555
* merely a copy of this one.
557
wrapDateLine: function(maxExtent, options) {
558
options = options || {};
560
var leftTolerance = options.leftTolerance || 0;
561
var rightTolerance = options.rightTolerance || 0;
563
var newBounds = this.clone();
568
while ( newBounds.left < maxExtent.left &&
569
(newBounds.right - rightTolerance) <= maxExtent.left ) {
570
newBounds = newBounds.add(maxExtent.getWidth(), 0);
574
while ( (newBounds.left + leftTolerance) >= maxExtent.right &&
575
newBounds.right > maxExtent.right ) {
576
newBounds = newBounds.add(-maxExtent.getWidth(), 0);
583
CLASS_NAME: "OpenLayers.Bounds"
587
* APIFunction: fromString
588
* Alternative constructor that builds a new OpenLayers.Bounds from a
592
* str - {String}Comma-separated bounds string. (ex. <i>"5,42,10,45"</i>)
595
* {<OpenLayers.Bounds>} New bounds object built from the
598
OpenLayers.Bounds.fromString = function(str) {
599
var bounds = str.split(",");
600
return OpenLayers.Bounds.fromArray(bounds);
604
* APIFunction: fromArray
605
* Alternative constructor that builds a new OpenLayers.Bounds
609
* bbox - {Array(Float)} Array of bounds values (ex. <i>[5,42,10,45]</i>)
612
* {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
614
OpenLayers.Bounds.fromArray = function(bbox) {
615
return new OpenLayers.Bounds(parseFloat(bbox[0]),
618
parseFloat(bbox[3]));
622
* APIFunction: fromSize
623
* Alternative constructor that builds a new OpenLayers.Bounds
627
* size - {<OpenLayers.Size>}
630
* {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
632
OpenLayers.Bounds.fromSize = function(size) {
633
return new OpenLayers.Bounds(0,
640
* Function: oppositeQuadrant
641
* Get the opposite quadrant for a given quadrant string.
644
* quadrant - {String} two character quadrant shortstring
647
* {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if
648
* you pass in "bl" it returns "tr", if you pass in "br" it
651
OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
654
opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
655
opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';