UNPKG

7.94 kBJavaScriptView Raw
1import {LatLng, toLatLng} from './LatLng';
2
3/*
4 * @class LatLngBounds
5 * @aka L.LatLngBounds
6 *
7 * Represents a rectangular geographical area on a map.
8 *
9 * @example
10 *
11 * ```js
12 * var corner1 = L.latLng(40.712, -74.227),
13 * corner2 = L.latLng(40.774, -74.125),
14 * bounds = L.latLngBounds(corner1, corner2);
15 * ```
16 *
17 * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
18 *
19 * ```js
20 * map.fitBounds([
21 * [40.712, -74.227],
22 * [40.774, -74.125]
23 * ]);
24 * ```
25 *
26 * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.
27 *
28 * Note that `LatLngBounds` does not inherit from Leafet's `Class` object,
29 * which means new classes can't inherit from it, and new methods
30 * can't be added to it with the `include` function.
31 */
32
33export function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
34 if (!corner1) { return; }
35
36 var latlngs = corner2 ? [corner1, corner2] : corner1;
37
38 for (var i = 0, len = latlngs.length; i < len; i++) {
39 this.extend(latlngs[i]);
40 }
41}
42
43LatLngBounds.prototype = {
44
45 // @method extend(latlng: LatLng): this
46 // Extend the bounds to contain the given point
47
48 // @alternative
49 // @method extend(otherBounds: LatLngBounds): this
50 // Extend the bounds to contain the given bounds
51 extend: function (obj) {
52 var sw = this._southWest,
53 ne = this._northEast,
54 sw2, ne2;
55
56 if (obj instanceof LatLng) {
57 sw2 = obj;
58 ne2 = obj;
59
60 } else if (obj instanceof LatLngBounds) {
61 sw2 = obj._southWest;
62 ne2 = obj._northEast;
63
64 if (!sw2 || !ne2) { return this; }
65
66 } else {
67 return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
68 }
69
70 if (!sw && !ne) {
71 this._southWest = new LatLng(sw2.lat, sw2.lng);
72 this._northEast = new LatLng(ne2.lat, ne2.lng);
73 } else {
74 sw.lat = Math.min(sw2.lat, sw.lat);
75 sw.lng = Math.min(sw2.lng, sw.lng);
76 ne.lat = Math.max(ne2.lat, ne.lat);
77 ne.lng = Math.max(ne2.lng, ne.lng);
78 }
79
80 return this;
81 },
82
83 // @method pad(bufferRatio: Number): LatLngBounds
84 // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
85 // For example, a ratio of 0.5 extends the bounds by 50% in each direction.
86 // Negative values will retract the bounds.
87 pad: function (bufferRatio) {
88 var sw = this._southWest,
89 ne = this._northEast,
90 heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
91 widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
92
93 return new LatLngBounds(
94 new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
95 new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
96 },
97
98 // @method getCenter(): LatLng
99 // Returns the center point of the bounds.
100 getCenter: function () {
101 return new LatLng(
102 (this._southWest.lat + this._northEast.lat) / 2,
103 (this._southWest.lng + this._northEast.lng) / 2);
104 },
105
106 // @method getSouthWest(): LatLng
107 // Returns the south-west point of the bounds.
108 getSouthWest: function () {
109 return this._southWest;
110 },
111
112 // @method getNorthEast(): LatLng
113 // Returns the north-east point of the bounds.
114 getNorthEast: function () {
115 return this._northEast;
116 },
117
118 // @method getNorthWest(): LatLng
119 // Returns the north-west point of the bounds.
120 getNorthWest: function () {
121 return new LatLng(this.getNorth(), this.getWest());
122 },
123
124 // @method getSouthEast(): LatLng
125 // Returns the south-east point of the bounds.
126 getSouthEast: function () {
127 return new LatLng(this.getSouth(), this.getEast());
128 },
129
130 // @method getWest(): Number
131 // Returns the west longitude of the bounds
132 getWest: function () {
133 return this._southWest.lng;
134 },
135
136 // @method getSouth(): Number
137 // Returns the south latitude of the bounds
138 getSouth: function () {
139 return this._southWest.lat;
140 },
141
142 // @method getEast(): Number
143 // Returns the east longitude of the bounds
144 getEast: function () {
145 return this._northEast.lng;
146 },
147
148 // @method getNorth(): Number
149 // Returns the north latitude of the bounds
150 getNorth: function () {
151 return this._northEast.lat;
152 },
153
154 // @method contains(otherBounds: LatLngBounds): Boolean
155 // Returns `true` if the rectangle contains the given one.
156
157 // @alternative
158 // @method contains (latlng: LatLng): Boolean
159 // Returns `true` if the rectangle contains the given point.
160 contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
161 if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
162 obj = toLatLng(obj);
163 } else {
164 obj = toLatLngBounds(obj);
165 }
166
167 var sw = this._southWest,
168 ne = this._northEast,
169 sw2, ne2;
170
171 if (obj instanceof LatLngBounds) {
172 sw2 = obj.getSouthWest();
173 ne2 = obj.getNorthEast();
174 } else {
175 sw2 = ne2 = obj;
176 }
177
178 return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
179 (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
180 },
181
182 // @method intersects(otherBounds: LatLngBounds): Boolean
183 // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
184 intersects: function (bounds) {
185 bounds = toLatLngBounds(bounds);
186
187 var sw = this._southWest,
188 ne = this._northEast,
189 sw2 = bounds.getSouthWest(),
190 ne2 = bounds.getNorthEast(),
191
192 latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
193 lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
194
195 return latIntersects && lngIntersects;
196 },
197
198 // @method overlaps(otherBounds: Bounds): Boolean
199 // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
200 overlaps: function (bounds) {
201 bounds = toLatLngBounds(bounds);
202
203 var sw = this._southWest,
204 ne = this._northEast,
205 sw2 = bounds.getSouthWest(),
206 ne2 = bounds.getNorthEast(),
207
208 latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
209 lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
210
211 return latOverlaps && lngOverlaps;
212 },
213
214 // @method toBBoxString(): String
215 // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
216 toBBoxString: function () {
217 return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
218 },
219
220 // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
221 // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.
222 equals: function (bounds, maxMargin) {
223 if (!bounds) { return false; }
224
225 bounds = toLatLngBounds(bounds);
226
227 return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
228 this._northEast.equals(bounds.getNorthEast(), maxMargin);
229 },
230
231 // @method isValid(): Boolean
232 // Returns `true` if the bounds are properly initialized.
233 isValid: function () {
234 return !!(this._southWest && this._northEast);
235 }
236};
237
238// TODO International date line?
239
240// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
241// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
242
243// @alternative
244// @factory L.latLngBounds(latlngs: LatLng[])
245// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
246export function toLatLngBounds(a, b) {
247 if (a instanceof LatLngBounds) {
248 return a;
249 }
250 return new LatLngBounds(a, b);
251}