PageRenderTime 4527ms CodeModel.GetById 55ms RepoModel.GetById 2ms app.codeStats 2ms

/ajax/libs/openlayers/2.12/OpenLayers.debug.js

https://bitbucket.org/kolbyjAFK/cdnjs
JavaScript | 14899 lines | 11931 code | 433 blank | 2535 comment | 547 complexity | 19ceef888620f331b6e2c80d6617606a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. OpenLayers.js -- OpenLayers Map Viewer Library
  3. Copyright (c) 2006-2012 by OpenLayers Contributors
  4. Published under the 2-clause BSD license.
  5. See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
  6. Includes compressed code under the following licenses:
  7. (For uncompressed versions of the code used, please see the
  8. OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
  9. */
  10. /**
  11. * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
  12. * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
  13. *
  14. * Licensed under the Apache License, Version 2.0 (the "License");
  15. * you may not use this file except in compliance with the License.
  16. * You may obtain a copy of the License at
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. */
  19. /**
  20. * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
  21. * Copyright (c) 2006, Yahoo! Inc.
  22. * All rights reserved.
  23. *
  24. * Redistribution and use of this software in source and binary forms, with or
  25. * without modification, are permitted provided that the following conditions
  26. * are met:
  27. *
  28. * * Redistributions of source code must retain the above copyright notice,
  29. * this list of conditions and the following disclaimer.
  30. *
  31. * * Redistributions in binary form must reproduce the above copyright notice,
  32. * this list of conditions and the following disclaimer in the documentation
  33. * and/or other materials provided with the distribution.
  34. *
  35. * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
  36. * used to endorse or promote products derived from this software without
  37. * specific prior written permission of Yahoo! Inc.
  38. *
  39. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  40. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  41. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  42. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  43. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  44. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  45. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  46. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  47. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  48. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  49. * POSSIBILITY OF SUCH DAMAGE.
  50. */
  51. /* ======================================================================
  52. OpenLayers/SingleFile.js
  53. ====================================================================== */
  54. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  55. * full list of contributors). Published under the 2-clause BSD license.
  56. * See license.txt in the OpenLayers distribution or repository for the
  57. * full text of the license. */
  58. var OpenLayers = {
  59. /**
  60. * Constant: VERSION_NUMBER
  61. */
  62. VERSION_NUMBER: "Release 2.12",
  63. /**
  64. * Constant: singleFile
  65. * TODO: remove this in 3.0 when we stop supporting build profiles that
  66. * include OpenLayers.js
  67. */
  68. singleFile: true,
  69. /**
  70. * Method: _getScriptLocation
  71. * Return the path to this script. This is also implemented in
  72. * OpenLayers.js
  73. *
  74. * Returns:
  75. * {String} Path to this script
  76. */
  77. _getScriptLocation: (function() {
  78. var r = new RegExp("(^|(.*?\\/))(OpenLayers[^\\/]*?\\.js)(\\?|$)"),
  79. s = document.getElementsByTagName('script'),
  80. src, m, l = "";
  81. for(var i=0, len=s.length; i<len; i++) {
  82. src = s[i].getAttribute('src');
  83. if(src) {
  84. m = src.match(r);
  85. if(m) {
  86. l = m[1];
  87. break;
  88. }
  89. }
  90. }
  91. return (function() { return l; });
  92. })(),
  93. /**
  94. * Property: ImgPath
  95. * {String} Set this to the path where control images are stored, a path
  96. * given here must end with a slash. If set to '' (which is the default)
  97. * OpenLayers will use its script location + "img/".
  98. *
  99. * You will need to set this property when you have a singlefile build of
  100. * OpenLayers that either is not named "OpenLayers.js" or if you move
  101. * the file in a way such that the image directory cannot be derived from
  102. * the script location.
  103. *
  104. * If your custom OpenLayers build is named "my-custom-ol.js" and the images
  105. * of OpenLayers are in a folder "/resources/external/images/ol" a correct
  106. * way of including OpenLayers in your HTML would be:
  107. *
  108. * (code)
  109. * <script src="/path/to/my-custom-ol.js" type="text/javascript"></script>
  110. * <script type="text/javascript">
  111. * // tell OpenLayers where the control images are
  112. * // remember the trailing slash
  113. * OpenLayers.ImgPath = "/resources/external/images/ol/";
  114. * </script>
  115. * (end code)
  116. *
  117. * Please remember that when your OpenLayers script is not named
  118. * "OpenLayers.js" you will have to make sure that the default theme is
  119. * loaded into the page by including an appropriate <link>-tag,
  120. * e.g.:
  121. *
  122. * (code)
  123. * <link rel="stylesheet" href="/path/to/default/style.css" type="text/css">
  124. * (end code)
  125. */
  126. ImgPath : ''
  127. };
  128. /* ======================================================================
  129. OpenLayers/BaseTypes/Class.js
  130. ====================================================================== */
  131. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  132. * full list of contributors). Published under the 2-clause BSD license.
  133. * See license.txt in the OpenLayers distribution or repository for the
  134. * full text of the license. */
  135. /**
  136. * @requires OpenLayers/SingleFile.js
  137. */
  138. /**
  139. * Constructor: OpenLayers.Class
  140. * Base class used to construct all other classes. Includes support for
  141. * multiple inheritance.
  142. *
  143. * This constructor is new in OpenLayers 2.5. At OpenLayers 3.0, the old
  144. * syntax for creating classes and dealing with inheritance
  145. * will be removed.
  146. *
  147. * To create a new OpenLayers-style class, use the following syntax:
  148. * (code)
  149. * var MyClass = OpenLayers.Class(prototype);
  150. * (end)
  151. *
  152. * To create a new OpenLayers-style class with multiple inheritance, use the
  153. * following syntax:
  154. * (code)
  155. * var MyClass = OpenLayers.Class(Class1, Class2, prototype);
  156. * (end)
  157. *
  158. * Note that instanceof reflection will only reveal Class1 as superclass.
  159. *
  160. */
  161. OpenLayers.Class = function() {
  162. var len = arguments.length;
  163. var P = arguments[0];
  164. var F = arguments[len-1];
  165. var C = typeof F.initialize == "function" ?
  166. F.initialize :
  167. function(){ P.prototype.initialize.apply(this, arguments); };
  168. if (len > 1) {
  169. var newArgs = [C, P].concat(
  170. Array.prototype.slice.call(arguments).slice(1, len-1), F);
  171. OpenLayers.inherit.apply(null, newArgs);
  172. } else {
  173. C.prototype = F;
  174. }
  175. return C;
  176. };
  177. /**
  178. * Function: OpenLayers.inherit
  179. *
  180. * Parameters:
  181. * C - {Object} the class that inherits
  182. * P - {Object} the superclass to inherit from
  183. *
  184. * In addition to the mandatory C and P parameters, an arbitrary number of
  185. * objects can be passed, which will extend C.
  186. */
  187. OpenLayers.inherit = function(C, P) {
  188. var F = function() {};
  189. F.prototype = P.prototype;
  190. C.prototype = new F;
  191. var i, l, o;
  192. for(i=2, l=arguments.length; i<l; i++) {
  193. o = arguments[i];
  194. if(typeof o === "function") {
  195. o = o.prototype;
  196. }
  197. OpenLayers.Util.extend(C.prototype, o);
  198. }
  199. };
  200. /**
  201. * APIFunction: extend
  202. * Copy all properties of a source object to a destination object. Modifies
  203. * the passed in destination object. Any properties on the source object
  204. * that are set to undefined will not be (re)set on the destination object.
  205. *
  206. * Parameters:
  207. * destination - {Object} The object that will be modified
  208. * source - {Object} The object with properties to be set on the destination
  209. *
  210. * Returns:
  211. * {Object} The destination object.
  212. */
  213. OpenLayers.Util = OpenLayers.Util || {};
  214. OpenLayers.Util.extend = function(destination, source) {
  215. destination = destination || {};
  216. if (source) {
  217. for (var property in source) {
  218. var value = source[property];
  219. if (value !== undefined) {
  220. destination[property] = value;
  221. }
  222. }
  223. /**
  224. * IE doesn't include the toString property when iterating over an object's
  225. * properties with the for(property in object) syntax. Explicitly check if
  226. * the source has its own toString property.
  227. */
  228. /*
  229. * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
  230. * prototype object" when calling hawOwnProperty if the source object
  231. * is an instance of window.Event.
  232. */
  233. var sourceIsEvt = typeof window.Event == "function"
  234. && source instanceof window.Event;
  235. if (!sourceIsEvt
  236. && source.hasOwnProperty && source.hasOwnProperty("toString")) {
  237. destination.toString = source.toString;
  238. }
  239. }
  240. return destination;
  241. };
  242. /* ======================================================================
  243. OpenLayers/BaseTypes.js
  244. ====================================================================== */
  245. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  246. * full list of contributors). Published under the 2-clause BSD license.
  247. * See license.txt in the OpenLayers distribution or repository for the
  248. * full text of the license. */
  249. /**
  250. * @requires OpenLayers/SingleFile.js
  251. */
  252. /**
  253. * Header: OpenLayers Base Types
  254. * OpenLayers custom string, number and function functions are described here.
  255. */
  256. /**
  257. * Namespace: OpenLayers.String
  258. * Contains convenience functions for string manipulation.
  259. */
  260. OpenLayers.String = {
  261. /**
  262. * APIFunction: startsWith
  263. * Test whether a string starts with another string.
  264. *
  265. * Parameters:
  266. * str - {String} The string to test.
  267. * sub - {String} The substring to look for.
  268. *
  269. * Returns:
  270. * {Boolean} The first string starts with the second.
  271. */
  272. startsWith: function(str, sub) {
  273. return (str.indexOf(sub) == 0);
  274. },
  275. /**
  276. * APIFunction: contains
  277. * Test whether a string contains another string.
  278. *
  279. * Parameters:
  280. * str - {String} The string to test.
  281. * sub - {String} The substring to look for.
  282. *
  283. * Returns:
  284. * {Boolean} The first string contains the second.
  285. */
  286. contains: function(str, sub) {
  287. return (str.indexOf(sub) != -1);
  288. },
  289. /**
  290. * APIFunction: trim
  291. * Removes leading and trailing whitespace characters from a string.
  292. *
  293. * Parameters:
  294. * str - {String} The (potentially) space padded string. This string is not
  295. * modified.
  296. *
  297. * Returns:
  298. * {String} A trimmed version of the string with all leading and
  299. * trailing spaces removed.
  300. */
  301. trim: function(str) {
  302. return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  303. },
  304. /**
  305. * APIFunction: camelize
  306. * Camel-case a hyphenated string.
  307. * Ex. "chicken-head" becomes "chickenHead", and
  308. * "-chicken-head" becomes "ChickenHead".
  309. *
  310. * Parameters:
  311. * str - {String} The string to be camelized. The original is not modified.
  312. *
  313. * Returns:
  314. * {String} The string, camelized
  315. */
  316. camelize: function(str) {
  317. var oStringList = str.split('-');
  318. var camelizedString = oStringList[0];
  319. for (var i=1, len=oStringList.length; i<len; i++) {
  320. var s = oStringList[i];
  321. camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
  322. }
  323. return camelizedString;
  324. },
  325. /**
  326. * APIFunction: format
  327. * Given a string with tokens in the form ${token}, return a string
  328. * with tokens replaced with properties from the given context
  329. * object. Represent a literal "${" by doubling it, e.g. "${${".
  330. *
  331. * Parameters:
  332. * template - {String} A string with tokens to be replaced. A template
  333. * has the form "literal ${token}" where the token will be replaced
  334. * by the value of context["token"].
  335. * context - {Object} An optional object with properties corresponding
  336. * to the tokens in the format string. If no context is sent, the
  337. * window object will be used.
  338. * args - {Array} Optional arguments to pass to any functions found in
  339. * the context. If a context property is a function, the token
  340. * will be replaced by the return from the function called with
  341. * these arguments.
  342. *
  343. * Returns:
  344. * {String} A string with tokens replaced from the context object.
  345. */
  346. format: function(template, context, args) {
  347. if(!context) {
  348. context = window;
  349. }
  350. // Example matching:
  351. // str = ${foo.bar}
  352. // match = foo.bar
  353. var replacer = function(str, match) {
  354. var replacement;
  355. // Loop through all subs. Example: ${a.b.c}
  356. // 0 -> replacement = context[a];
  357. // 1 -> replacement = context[a][b];
  358. // 2 -> replacement = context[a][b][c];
  359. var subs = match.split(/\.+/);
  360. for (var i=0; i< subs.length; i++) {
  361. if (i == 0) {
  362. replacement = context;
  363. }
  364. replacement = replacement[subs[i]];
  365. }
  366. if(typeof replacement == "function") {
  367. replacement = args ?
  368. replacement.apply(null, args) :
  369. replacement();
  370. }
  371. // If replacement is undefined, return the string 'undefined'.
  372. // This is a workaround for a bugs in browsers not properly
  373. // dealing with non-participating groups in regular expressions:
  374. // http://blog.stevenlevithan.com/archives/npcg-javascript
  375. if (typeof replacement == 'undefined') {
  376. return 'undefined';
  377. } else {
  378. return replacement;
  379. }
  380. };
  381. return template.replace(OpenLayers.String.tokenRegEx, replacer);
  382. },
  383. /**
  384. * Property: tokenRegEx
  385. * Used to find tokens in a string.
  386. * Examples: ${a}, ${a.b.c}, ${a-b}, ${5}
  387. */
  388. tokenRegEx: /\$\{([\w.]+?)\}/g,
  389. /**
  390. * Property: numberRegEx
  391. * Used to test strings as numbers.
  392. */
  393. numberRegEx: /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,
  394. /**
  395. * APIFunction: isNumeric
  396. * Determine whether a string contains only a numeric value.
  397. *
  398. * Examples:
  399. * (code)
  400. * OpenLayers.String.isNumeric("6.02e23") // true
  401. * OpenLayers.String.isNumeric("12 dozen") // false
  402. * OpenLayers.String.isNumeric("4") // true
  403. * OpenLayers.String.isNumeric(" 4 ") // false
  404. * (end)
  405. *
  406. * Returns:
  407. * {Boolean} String contains only a number.
  408. */
  409. isNumeric: function(value) {
  410. return OpenLayers.String.numberRegEx.test(value);
  411. },
  412. /**
  413. * APIFunction: numericIf
  414. * Converts a string that appears to be a numeric value into a number.
  415. *
  416. * Parameters:
  417. * value - {String}
  418. *
  419. * Returns:
  420. * {Number|String} a Number if the passed value is a number, a String
  421. * otherwise.
  422. */
  423. numericIf: function(value) {
  424. return OpenLayers.String.isNumeric(value) ? parseFloat(value) : value;
  425. }
  426. };
  427. /**
  428. * Namespace: OpenLayers.Number
  429. * Contains convenience functions for manipulating numbers.
  430. */
  431. OpenLayers.Number = {
  432. /**
  433. * Property: decimalSeparator
  434. * Decimal separator to use when formatting numbers.
  435. */
  436. decimalSeparator: ".",
  437. /**
  438. * Property: thousandsSeparator
  439. * Thousands separator to use when formatting numbers.
  440. */
  441. thousandsSeparator: ",",
  442. /**
  443. * APIFunction: limitSigDigs
  444. * Limit the number of significant digits on a float.
  445. *
  446. * Parameters:
  447. * num - {Float}
  448. * sig - {Integer}
  449. *
  450. * Returns:
  451. * {Float} The number, rounded to the specified number of significant
  452. * digits.
  453. */
  454. limitSigDigs: function(num, sig) {
  455. var fig = 0;
  456. if (sig > 0) {
  457. fig = parseFloat(num.toPrecision(sig));
  458. }
  459. return fig;
  460. },
  461. /**
  462. * APIFunction: format
  463. * Formats a number for output.
  464. *
  465. * Parameters:
  466. * num - {Float}
  467. * dec - {Integer} Number of decimal places to round to.
  468. * Defaults to 0. Set to null to leave decimal places unchanged.
  469. * tsep - {String} Thousands separator.
  470. * Default is ",".
  471. * dsep - {String} Decimal separator.
  472. * Default is ".".
  473. *
  474. * Returns:
  475. * {String} A string representing the formatted number.
  476. */
  477. format: function(num, dec, tsep, dsep) {
  478. dec = (typeof dec != "undefined") ? dec : 0;
  479. tsep = (typeof tsep != "undefined") ? tsep :
  480. OpenLayers.Number.thousandsSeparator;
  481. dsep = (typeof dsep != "undefined") ? dsep :
  482. OpenLayers.Number.decimalSeparator;
  483. if (dec != null) {
  484. num = parseFloat(num.toFixed(dec));
  485. }
  486. var parts = num.toString().split(".");
  487. if (parts.length == 1 && dec == null) {
  488. // integer where we do not want to touch the decimals
  489. dec = 0;
  490. }
  491. var integer = parts[0];
  492. if (tsep) {
  493. var thousands = /(-?[0-9]+)([0-9]{3})/;
  494. while(thousands.test(integer)) {
  495. integer = integer.replace(thousands, "$1" + tsep + "$2");
  496. }
  497. }
  498. var str;
  499. if (dec == 0) {
  500. str = integer;
  501. } else {
  502. var rem = parts.length > 1 ? parts[1] : "0";
  503. if (dec != null) {
  504. rem = rem + new Array(dec - rem.length + 1).join("0");
  505. }
  506. str = integer + dsep + rem;
  507. }
  508. return str;
  509. }
  510. };
  511. /**
  512. * Namespace: OpenLayers.Function
  513. * Contains convenience functions for function manipulation.
  514. */
  515. OpenLayers.Function = {
  516. /**
  517. * APIFunction: bind
  518. * Bind a function to an object. Method to easily create closures with
  519. * 'this' altered.
  520. *
  521. * Parameters:
  522. * func - {Function} Input function.
  523. * object - {Object} The object to bind to the input function (as this).
  524. *
  525. * Returns:
  526. * {Function} A closure with 'this' set to the passed in object.
  527. */
  528. bind: function(func, object) {
  529. // create a reference to all arguments past the second one
  530. var args = Array.prototype.slice.apply(arguments, [2]);
  531. return function() {
  532. // Push on any additional arguments from the actual function call.
  533. // These will come after those sent to the bind call.
  534. var newArgs = args.concat(
  535. Array.prototype.slice.apply(arguments, [0])
  536. );
  537. return func.apply(object, newArgs);
  538. };
  539. },
  540. /**
  541. * APIFunction: bindAsEventListener
  542. * Bind a function to an object, and configure it to receive the event
  543. * object as first parameter when called.
  544. *
  545. * Parameters:
  546. * func - {Function} Input function to serve as an event listener.
  547. * object - {Object} A reference to this.
  548. *
  549. * Returns:
  550. * {Function}
  551. */
  552. bindAsEventListener: function(func, object) {
  553. return function(event) {
  554. return func.call(object, event || window.event);
  555. };
  556. },
  557. /**
  558. * APIFunction: False
  559. * A simple function to that just does "return false". We use this to
  560. * avoid attaching anonymous functions to DOM event handlers, which
  561. * causes "issues" on IE<8.
  562. *
  563. * Usage:
  564. * document.onclick = OpenLayers.Function.False;
  565. *
  566. * Returns:
  567. * {Boolean}
  568. */
  569. False : function() {
  570. return false;
  571. },
  572. /**
  573. * APIFunction: True
  574. * A simple function to that just does "return true". We use this to
  575. * avoid attaching anonymous functions to DOM event handlers, which
  576. * causes "issues" on IE<8.
  577. *
  578. * Usage:
  579. * document.onclick = OpenLayers.Function.True;
  580. *
  581. * Returns:
  582. * {Boolean}
  583. */
  584. True : function() {
  585. return true;
  586. },
  587. /**
  588. * APIFunction: Void
  589. * A reusable function that returns ``undefined``.
  590. *
  591. * Returns:
  592. * {undefined}
  593. */
  594. Void: function() {}
  595. };
  596. /**
  597. * Namespace: OpenLayers.Array
  598. * Contains convenience functions for array manipulation.
  599. */
  600. OpenLayers.Array = {
  601. /**
  602. * APIMethod: filter
  603. * Filter an array. Provides the functionality of the
  604. * Array.prototype.filter extension to the ECMA-262 standard. Where
  605. * available, Array.prototype.filter will be used.
  606. *
  607. * Based on well known example from http://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Array/filter
  608. *
  609. * Parameters:
  610. * array - {Array} The array to be filtered. This array is not mutated.
  611. * Elements added to this array by the callback will not be visited.
  612. * callback - {Function} A function that is called for each element in
  613. * the array. If this function returns true, the element will be
  614. * included in the return. The function will be called with three
  615. * arguments: the element in the array, the index of that element, and
  616. * the array itself. If the optional caller parameter is specified
  617. * the callback will be called with this set to caller.
  618. * caller - {Object} Optional object to be set as this when the callback
  619. * is called.
  620. *
  621. * Returns:
  622. * {Array} An array of elements from the passed in array for which the
  623. * callback returns true.
  624. */
  625. filter: function(array, callback, caller) {
  626. var selected = [];
  627. if (Array.prototype.filter) {
  628. selected = array.filter(callback, caller);
  629. } else {
  630. var len = array.length;
  631. if (typeof callback != "function") {
  632. throw new TypeError();
  633. }
  634. for(var i=0; i<len; i++) {
  635. if (i in array) {
  636. var val = array[i];
  637. if (callback.call(caller, val, i, array)) {
  638. selected.push(val);
  639. }
  640. }
  641. }
  642. }
  643. return selected;
  644. }
  645. };
  646. /* ======================================================================
  647. OpenLayers/BaseTypes/Bounds.js
  648. ====================================================================== */
  649. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  650. * full list of contributors). Published under the 2-clause BSD license.
  651. * See license.txt in the OpenLayers distribution or repository for the
  652. * full text of the license. */
  653. /**
  654. * @requires OpenLayers/BaseTypes/Class.js
  655. */
  656. /**
  657. * Class: OpenLayers.Bounds
  658. * Instances of this class represent bounding boxes. Data stored as left,
  659. * bottom, right, top floats. All values are initialized to null, however,
  660. * you should make sure you set them before using the bounds for anything.
  661. *
  662. * Possible use case:
  663. * (code)
  664. * bounds = new OpenLayers.Bounds();
  665. * bounds.extend(new OpenLayers.LonLat(4,5));
  666. * bounds.extend(new OpenLayers.LonLat(5,6));
  667. * bounds.toBBOX(); // returns 4,5,5,6
  668. * (end)
  669. */
  670. OpenLayers.Bounds = OpenLayers.Class({
  671. /**
  672. * Property: left
  673. * {Number} Minimum horizontal coordinate.
  674. */
  675. left: null,
  676. /**
  677. * Property: bottom
  678. * {Number} Minimum vertical coordinate.
  679. */
  680. bottom: null,
  681. /**
  682. * Property: right
  683. * {Number} Maximum horizontal coordinate.
  684. */
  685. right: null,
  686. /**
  687. * Property: top
  688. * {Number} Maximum vertical coordinate.
  689. */
  690. top: null,
  691. /**
  692. * Property: centerLonLat
  693. * {<OpenLayers.LonLat>} A cached center location. This should not be
  694. * accessed directly. Use <getCenterLonLat> instead.
  695. */
  696. centerLonLat: null,
  697. /**
  698. * Constructor: OpenLayers.Bounds
  699. * Construct a new bounds object. Coordinates can either be passed as four
  700. * arguments, or as a single argument.
  701. *
  702. * Parameters (four arguments):
  703. * left - {Number} The left bounds of the box. Note that for width
  704. * calculations, this is assumed to be less than the right value.
  705. * bottom - {Number} The bottom bounds of the box. Note that for height
  706. * calculations, this is assumed to be more than the top value.
  707. * right - {Number} The right bounds.
  708. * top - {Number} The top bounds.
  709. *
  710. * Parameters (single argument):
  711. * bounds - {Array(Number)} [left, bottom, right, top]
  712. */
  713. initialize: function(left, bottom, right, top) {
  714. if (OpenLayers.Util.isArray(left)) {
  715. top = left[3];
  716. right = left[2];
  717. bottom = left[1];
  718. left = left[0];
  719. }
  720. if (left != null) {
  721. this.left = OpenLayers.Util.toFloat(left);
  722. }
  723. if (bottom != null) {
  724. this.bottom = OpenLayers.Util.toFloat(bottom);
  725. }
  726. if (right != null) {
  727. this.right = OpenLayers.Util.toFloat(right);
  728. }
  729. if (top != null) {
  730. this.top = OpenLayers.Util.toFloat(top);
  731. }
  732. },
  733. /**
  734. * Method: clone
  735. * Create a cloned instance of this bounds.
  736. *
  737. * Returns:
  738. * {<OpenLayers.Bounds>} A fresh copy of the bounds
  739. */
  740. clone:function() {
  741. return new OpenLayers.Bounds(this.left, this.bottom,
  742. this.right, this.top);
  743. },
  744. /**
  745. * Method: equals
  746. * Test a two bounds for equivalence.
  747. *
  748. * Parameters:
  749. * bounds - {<OpenLayers.Bounds>}
  750. *
  751. * Returns:
  752. * {Boolean} The passed-in bounds object has the same left,
  753. * right, top, bottom components as this. Note that if bounds
  754. * passed in is null, returns false.
  755. */
  756. equals:function(bounds) {
  757. var equals = false;
  758. if (bounds != null) {
  759. equals = ((this.left == bounds.left) &&
  760. (this.right == bounds.right) &&
  761. (this.top == bounds.top) &&
  762. (this.bottom == bounds.bottom));
  763. }
  764. return equals;
  765. },
  766. /**
  767. * APIMethod: toString
  768. *
  769. * Returns:
  770. * {String} String representation of bounds object.
  771. */
  772. toString:function() {
  773. return [this.left, this.bottom, this.right, this.top].join(",");
  774. },
  775. /**
  776. * APIMethod: toArray
  777. *
  778. * Parameters:
  779. * reverseAxisOrder - {Boolean} Should we reverse the axis order?
  780. *
  781. * Returns:
  782. * {Array} array of left, bottom, right, top
  783. */
  784. toArray: function(reverseAxisOrder) {
  785. if (reverseAxisOrder === true) {
  786. return [this.bottom, this.left, this.top, this.right];
  787. } else {
  788. return [this.left, this.bottom, this.right, this.top];
  789. }
  790. },
  791. /**
  792. * APIMethod: toBBOX
  793. *
  794. * Parameters:
  795. * decimal - {Integer} How many significant digits in the bbox coords?
  796. * Default is 6
  797. * reverseAxisOrder - {Boolean} Should we reverse the axis order?
  798. *
  799. * Returns:
  800. * {String} Simple String representation of bounds object.
  801. * (e.g. <i>"5,42,10,45"</i>)
  802. */
  803. toBBOX:function(decimal, reverseAxisOrder) {
  804. if (decimal== null) {
  805. decimal = 6;
  806. }
  807. var mult = Math.pow(10, decimal);
  808. var xmin = Math.round(this.left * mult) / mult;
  809. var ymin = Math.round(this.bottom * mult) / mult;
  810. var xmax = Math.round(this.right * mult) / mult;
  811. var ymax = Math.round(this.top * mult) / mult;
  812. if (reverseAxisOrder === true) {
  813. return ymin + "," + xmin + "," + ymax + "," + xmax;
  814. } else {
  815. return xmin + "," + ymin + "," + xmax + "," + ymax;
  816. }
  817. },
  818. /**
  819. * APIMethod: toGeometry
  820. * Create a new polygon geometry based on this bounds.
  821. *
  822. * Returns:
  823. * {<OpenLayers.Geometry.Polygon>} A new polygon with the coordinates
  824. * of this bounds.
  825. */
  826. toGeometry: function() {
  827. return new OpenLayers.Geometry.Polygon([
  828. new OpenLayers.Geometry.LinearRing([
  829. new OpenLayers.Geometry.Point(this.left, this.bottom),
  830. new OpenLayers.Geometry.Point(this.right, this.bottom),
  831. new OpenLayers.Geometry.Point(this.right, this.top),
  832. new OpenLayers.Geometry.Point(this.left, this.top)
  833. ])
  834. ]);
  835. },
  836. /**
  837. * APIMethod: getWidth
  838. *
  839. * Returns:
  840. * {Float} The width of the bounds
  841. */
  842. getWidth:function() {
  843. return (this.right - this.left);
  844. },
  845. /**
  846. * APIMethod: getHeight
  847. *
  848. * Returns:
  849. * {Float} The height of the bounds (top minus bottom).
  850. */
  851. getHeight:function() {
  852. return (this.top - this.bottom);
  853. },
  854. /**
  855. * APIMethod: getSize
  856. *
  857. * Returns:
  858. * {<OpenLayers.Size>} The size of the box.
  859. */
  860. getSize:function() {
  861. return new OpenLayers.Size(this.getWidth(), this.getHeight());
  862. },
  863. /**
  864. * APIMethod: getCenterPixel
  865. *
  866. * Returns:
  867. * {<OpenLayers.Pixel>} The center of the bounds in pixel space.
  868. */
  869. getCenterPixel:function() {
  870. return new OpenLayers.Pixel( (this.left + this.right) / 2,
  871. (this.bottom + this.top) / 2);
  872. },
  873. /**
  874. * APIMethod: getCenterLonLat
  875. *
  876. * Returns:
  877. * {<OpenLayers.LonLat>} The center of the bounds in map space.
  878. */
  879. getCenterLonLat:function() {
  880. if(!this.centerLonLat) {
  881. this.centerLonLat = new OpenLayers.LonLat(
  882. (this.left + this.right) / 2, (this.bottom + this.top) / 2
  883. );
  884. }
  885. return this.centerLonLat;
  886. },
  887. /**
  888. * APIMethod: scale
  889. * Scales the bounds around a pixel or lonlat. Note that the new
  890. * bounds may return non-integer properties, even if a pixel
  891. * is passed.
  892. *
  893. * Parameters:
  894. * ratio - {Float}
  895. * origin - {<OpenLayers.Pixel> or <OpenLayers.LonLat>}
  896. * Default is center.
  897. *
  898. * Returns:
  899. * {<OpenLayers.Bounds>} A new bounds that is scaled by ratio
  900. * from origin.
  901. */
  902. scale: function(ratio, origin){
  903. if(origin == null){
  904. origin = this.getCenterLonLat();
  905. }
  906. var origx,origy;
  907. // get origin coordinates
  908. if(origin.CLASS_NAME == "OpenLayers.LonLat"){
  909. origx = origin.lon;
  910. origy = origin.lat;
  911. } else {
  912. origx = origin.x;
  913. origy = origin.y;
  914. }
  915. var left = (this.left - origx) * ratio + origx;
  916. var bottom = (this.bottom - origy) * ratio + origy;
  917. var right = (this.right - origx) * ratio + origx;
  918. var top = (this.top - origy) * ratio + origy;
  919. return new OpenLayers.Bounds(left, bottom, right, top);
  920. },
  921. /**
  922. * APIMethod: add
  923. *
  924. * Parameters:
  925. * x - {Float}
  926. * y - {Float}
  927. *
  928. * Returns:
  929. * {<OpenLayers.Bounds>} A new bounds whose coordinates are the same as
  930. * this, but shifted by the passed-in x and y values.
  931. */
  932. add:function(x, y) {
  933. if ( (x == null) || (y == null) ) {
  934. throw new TypeError('Bounds.add cannot receive null values');
  935. }
  936. return new OpenLayers.Bounds(this.left + x, this.bottom + y,
  937. this.right + x, this.top + y);
  938. },
  939. /**
  940. * APIMethod: extend
  941. * Extend the bounds to include the point, lonlat, or bounds specified.
  942. * Note, this function assumes that left < right and bottom < top.
  943. *
  944. * Parameters:
  945. * object - {Object} Can be LonLat, Point, or Bounds
  946. */
  947. extend:function(object) {
  948. var bounds = null;
  949. if (object) {
  950. // clear cached center location
  951. switch(object.CLASS_NAME) {
  952. case "OpenLayers.LonLat":
  953. bounds = new OpenLayers.Bounds(object.lon, object.lat,
  954. object.lon, object.lat);
  955. break;
  956. case "OpenLayers.Geometry.Point":
  957. bounds = new OpenLayers.Bounds(object.x, object.y,
  958. object.x, object.y);
  959. break;
  960. case "OpenLayers.Bounds":
  961. bounds = object;
  962. break;
  963. }
  964. if (bounds) {
  965. this.centerLonLat = null;
  966. if ( (this.left == null) || (bounds.left < this.left)) {
  967. this.left = bounds.left;
  968. }
  969. if ( (this.bottom == null) || (bounds.bottom < this.bottom) ) {
  970. this.bottom = bounds.bottom;
  971. }
  972. if ( (this.right == null) || (bounds.right > this.right) ) {
  973. this.right = bounds.right;
  974. }
  975. if ( (this.top == null) || (bounds.top > this.top) ) {
  976. this.top = bounds.top;
  977. }
  978. }
  979. }
  980. },
  981. /**
  982. * APIMethod: containsLonLat
  983. *
  984. * Parameters:
  985. * ll - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
  986. * object with a 'lon' and 'lat' properties.
  987. * options - {Object} Optional parameters
  988. *
  989. * Acceptable options:
  990. * inclusive - {Boolean} Whether or not to include the border.
  991. * Default is true.
  992. * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, the
  993. * ll will be considered as contained if it exceeds the world bounds,
  994. * but can be wrapped around the dateline so it is contained by this
  995. * bounds.
  996. *
  997. * Returns:
  998. * {Boolean} The passed-in lonlat is within this bounds.
  999. */
  1000. containsLonLat: function(ll, options) {
  1001. if (typeof options === "boolean") {
  1002. options = {inclusive: options};
  1003. }
  1004. options = options || {};
  1005. var contains = this.contains(ll.lon, ll.lat, options.inclusive),
  1006. worldBounds = options.worldBounds;
  1007. if (worldBounds && !contains) {
  1008. var worldWidth = worldBounds.getWidth();
  1009. var worldCenterX = (worldBounds.left + worldBounds.right) / 2;
  1010. var worldsAway = Math.round((ll.lon - worldCenterX) / worldWidth);
  1011. contains = this.containsLonLat({
  1012. lon: ll.lon - worldsAway * worldWidth,
  1013. lat: ll.lat
  1014. }, {inclusive: options.inclusive});
  1015. }
  1016. return contains;
  1017. },
  1018. /**
  1019. * APIMethod: containsPixel
  1020. *
  1021. * Parameters:
  1022. * px - {<OpenLayers.Pixel>}
  1023. * inclusive - {Boolean} Whether or not to include the border. Default is
  1024. * true.
  1025. *
  1026. * Returns:
  1027. * {Boolean} The passed-in pixel is within this bounds.
  1028. */
  1029. containsPixel:function(px, inclusive) {
  1030. return this.contains(px.x, px.y, inclusive);
  1031. },
  1032. /**
  1033. * APIMethod: contains
  1034. *
  1035. * Parameters:
  1036. * x - {Float}
  1037. * y - {Float}
  1038. * inclusive - {Boolean} Whether or not to include the border. Default is
  1039. * true.
  1040. *
  1041. * Returns:
  1042. * {Boolean} Whether or not the passed-in coordinates are within this
  1043. * bounds.
  1044. */
  1045. contains:function(x, y, inclusive) {
  1046. //set default
  1047. if (inclusive == null) {
  1048. inclusive = true;
  1049. }
  1050. if (x == null || y == null) {
  1051. return false;
  1052. }
  1053. x = OpenLayers.Util.toFloat(x);
  1054. y = OpenLayers.Util.toFloat(y);
  1055. var contains = false;
  1056. if (inclusive) {
  1057. contains = ((x >= this.left) && (x <= this.right) &&
  1058. (y >= this.bottom) && (y <= this.top));
  1059. } else {
  1060. contains = ((x > this.left) && (x < this.right) &&
  1061. (y > this.bottom) && (y < this.top));
  1062. }
  1063. return contains;
  1064. },
  1065. /**
  1066. * APIMethod: intersectsBounds
  1067. * Determine whether the target bounds intersects this bounds. Bounds are
  1068. * considered intersecting if any of their edges intersect or if one
  1069. * bounds contains the other.
  1070. *
  1071. * Parameters:
  1072. * bounds - {<OpenLayers.Bounds>} The target bounds.
  1073. * options - {Object} Optional parameters.
  1074. *
  1075. * Acceptable options:
  1076. * inclusive - {Boolean} Treat coincident borders as intersecting. Default
  1077. * is true. If false, bounds that do not overlap but only touch at the
  1078. * border will not be considered as intersecting.
  1079. * worldBounds - {<OpenLayers.Bounds>} If a worldBounds is provided, two
  1080. * bounds will be considered as intersecting if they intersect when
  1081. * shifted to within the world bounds. This applies only to bounds that
  1082. * cross or are completely outside the world bounds.
  1083. *
  1084. * Returns:
  1085. * {Boolean} The passed-in bounds object intersects this bounds.
  1086. */
  1087. intersectsBounds:function(bounds, options) {
  1088. if (typeof options === "boolean") {
  1089. options = {inclusive: options};
  1090. }
  1091. options = options || {};
  1092. if (options.worldBounds) {
  1093. var self = this.wrapDateLine(options.worldBounds);
  1094. bounds = bounds.wrapDateLine(options.worldBounds);
  1095. } else {
  1096. self = this;
  1097. }
  1098. if (options.inclusive == null) {
  1099. options.inclusive = true;
  1100. }
  1101. var intersects = false;
  1102. var mightTouch = (
  1103. self.left == bounds.right ||
  1104. self.right == bounds.left ||
  1105. self.top == bounds.bottom ||
  1106. self.bottom == bounds.top
  1107. );
  1108. // if the two bounds only touch at an edge, and inclusive is false,
  1109. // then the bounds don't *really* intersect.
  1110. if (options.inclusive || !mightTouch) {
  1111. // otherwise, if one of the boundaries even partially contains another,
  1112. // inclusive of the edges, then they do intersect.
  1113. var inBottom = (
  1114. ((bounds.bottom >= self.bottom) && (bounds.bottom <= self.top)) ||
  1115. ((self.bottom >= bounds.bottom) && (self.bottom <= bounds.top))
  1116. );
  1117. var inTop = (
  1118. ((bounds.top >= self.bottom) && (bounds.top <= self.top)) ||
  1119. ((self.top > bounds.bottom) && (self.top < bounds.top))
  1120. );
  1121. var inLeft = (
  1122. ((bounds.left >= self.left) && (bounds.left <= self.right)) ||
  1123. ((self.left >= bounds.left) && (self.left <= bounds.right))
  1124. );
  1125. var inRight = (
  1126. ((bounds.right >= self.left) && (bounds.right <= self.right)) ||
  1127. ((self.right >= bounds.left) && (self.right <= bounds.right))
  1128. );
  1129. intersects = ((inBottom || inTop) && (inLeft || inRight));
  1130. }
  1131. // document me
  1132. if (options.worldBounds && !intersects) {
  1133. var world = options.worldBounds;
  1134. var width = world.getWidth();
  1135. var selfCrosses = !world.containsBounds(self);
  1136. var boundsCrosses = !world.containsBounds(bounds);
  1137. if (selfCrosses && !boundsCrosses) {
  1138. bounds = bounds.add(-width, 0);
  1139. intersects = self.intersectsBounds(bounds, {inclusive: options.inclusive});
  1140. } else if (boundsCrosses && !selfCrosses) {
  1141. self = self.add(-width, 0);
  1142. intersects = bounds.intersectsBounds(self, {inclusive: options.inclusive});
  1143. }
  1144. }
  1145. return intersects;
  1146. },
  1147. /**
  1148. * APIMethod: containsBounds
  1149. * Determine whether the target bounds is contained within this bounds.
  1150. *
  1151. * bounds - {<OpenLayers.Bounds>} The target bounds.
  1152. * partial - {Boolean} If any of the target corners is within this bounds
  1153. * consider the bounds contained. Default is false. If false, the
  1154. * entire target bounds must be contained within this bounds.
  1155. * inclusive - {Boolean} Treat shared edges as contained. Default is
  1156. * true.
  1157. *
  1158. * Returns:
  1159. * {Boolean} The passed-in bounds object is contained within this bounds.
  1160. */
  1161. containsBounds:function(bounds, partial, inclusive) {
  1162. if (partial == null) {
  1163. partial = false;
  1164. }
  1165. if (inclusive == null) {
  1166. inclusive = true;
  1167. }
  1168. var bottomLeft = this.contains(bounds.left, bounds.bottom, inclusive);
  1169. var bottomRight = this.contains(bounds.right, bounds.bottom, inclusive);
  1170. var topLeft = this.contains(bounds.left, bounds.top, inclusive);
  1171. var topRight = this.contains(bounds.right, bounds.top, inclusive);
  1172. return (partial) ? (bottomLeft || bottomRight || topLeft || topRight)
  1173. : (bottomLeft && bottomRight && topLeft && topRight);
  1174. },
  1175. /**
  1176. * APIMethod: determineQuadrant
  1177. *
  1178. * Parameters:
  1179. * lonlat - {<OpenLayers.LonLat>}
  1180. *
  1181. * Returns:
  1182. * {String} The quadrant ("br" "tr" "tl" "bl") of the bounds in which the
  1183. * coordinate lies.
  1184. */
  1185. determineQuadrant: function(lonlat) {
  1186. var quadrant = "";
  1187. var center = this.getCenterLonLat();
  1188. quadrant += (lonlat.lat < center.lat) ? "b" : "t";
  1189. quadrant += (lonlat.lon < center.lon) ? "l" : "r";
  1190. return quadrant;
  1191. },
  1192. /**
  1193. * APIMethod: transform
  1194. * Transform the Bounds object from source to dest.
  1195. *
  1196. * Parameters:
  1197. * source - {<OpenLayers.Projection>} Source projection.
  1198. * dest - {<OpenLayers.Projection>} Destination projection.
  1199. *
  1200. * Returns:
  1201. * {<OpenLayers.Bounds>} Itself, for use in chaining operations.
  1202. */
  1203. transform: function(source, dest) {
  1204. // clear cached center location
  1205. this.centerLonLat = null;
  1206. var ll = OpenLayers.Projection.transform(
  1207. {'x': this.left, 'y': this.bottom}, source, dest);
  1208. var lr = OpenLayers.Projection.transform(
  1209. {'x': this.right, 'y': this.bottom}, source, dest);
  1210. var ul = OpenLayers.Projection.transform(
  1211. {'x': this.left, 'y': this.top}, source, dest);
  1212. var ur = OpenLayers.Projection.transform(
  1213. {'x': this.right, 'y': this.top}, source, dest);
  1214. this.left = Math.min(ll.x, ul.x);
  1215. this.bottom = Math.min(ll.y, lr.y);
  1216. this.right = Math.max(lr.x, ur.x);
  1217. this.top = Math.max(ul.y, ur.y);
  1218. return this;
  1219. },
  1220. /**
  1221. * APIMethod: wrapDateLine
  1222. *
  1223. * Parameters:
  1224. * maxExtent - {<OpenLayers.Bounds>}
  1225. * options - {Object} Some possible options are:
  1226. *
  1227. * Allowed Options:
  1228. * leftTolerance - {float} Allow for a margin of error
  1229. * with the 'left' value of this
  1230. * bound.
  1231. * Default is 0.
  1232. * rightTolerance - {float} Allow for a margin of error
  1233. * with the 'right' value of
  1234. * this bound.
  1235. * Default is 0.
  1236. *
  1237. * Returns:
  1238. * {<OpenLayers.Bounds>} A copy of this bounds, but wrapped around the
  1239. * "dateline" (as specified by the borders of
  1240. * maxExtent). Note that this function only returns
  1241. * a different bounds value if this bounds is
  1242. * *entirely* outside of the maxExtent. If this
  1243. * bounds straddles the dateline (is part in/part
  1244. * out of maxExtent), the returned bounds will always
  1245. * cross the left edge of the given maxExtent.
  1246. *.
  1247. */
  1248. wrapDateLine: function(maxExtent, options) {
  1249. options = options || {};
  1250. var leftTolerance = options.leftTolerance || 0;
  1251. var rightTolerance = options.rightTolerance || 0;
  1252. var newBounds = this.clone();
  1253. if (maxExtent) {
  1254. var width = maxExtent.getWidth();
  1255. //shift right?
  1256. while (newBounds.left < maxExtent.left &&
  1257. newBounds.right - rightTolerance <= maxExtent.left ) {
  1258. newBounds = newBounds.add(width, 0);
  1259. }
  1260. //shift left?
  1261. while (newBounds.left + leftTolerance >= maxExtent.right &&
  1262. newBounds.right > maxExtent.right ) {
  1263. newBounds = newBounds.add(-width, 0);
  1264. }
  1265. // crosses right only? force left
  1266. var newLeft = newBounds.left + leftTolerance;
  1267. if (newLeft < maxExtent.right && newLeft > maxExtent.left &&
  1268. newBounds.right - rightTolerance > maxExtent.right) {
  1269. newBounds = newBounds.add(-width, 0);
  1270. }
  1271. }
  1272. return newBounds;
  1273. },
  1274. CLASS_NAME: "OpenLayers.Bounds"
  1275. });
  1276. /**
  1277. * APIFunction: fromString
  1278. * Alternative constructor that builds a new OpenLayers.Bounds from a
  1279. * parameter string
  1280. *
  1281. * Parameters:
  1282. * str - {String}Comma-separated bounds string. (e.g. <i>"5,42,10,45"</i>)
  1283. * reverseAxisOrder - {Boolean} Does the string use reverse axis order?
  1284. *
  1285. * Returns:
  1286. * {<OpenLayers.Bounds>} New bounds object built from the
  1287. * passed-in String.
  1288. */
  1289. OpenLayers.Bounds.fromString = function(str, reverseAxisOrder) {
  1290. var bounds = str.split(",");
  1291. return OpenLayers.Bounds.fromArray(bounds, reverseAxisOrder);
  1292. };
  1293. /**
  1294. * APIFunction: fromArray
  1295. * Alternative constructor that builds a new OpenLayers.Bounds
  1296. * from an array
  1297. *
  1298. * Parameters:
  1299. * bbox - {Array(Float)} Array of bounds values (e.g. <i>[5,42,10,45]</i>)
  1300. * reverseAxisOrder - {Boolean} Does the array use reverse axis order?
  1301. *
  1302. * Returns:
  1303. * {<OpenLayers.Bounds>} New bounds object built from the passed-in Array.
  1304. */
  1305. OpenLayers.Bounds.fromArray = function(bbox, reverseAxisOrder) {
  1306. return reverseAxisOrder === true ?
  1307. new OpenLayers.Bounds(bbox[1], bbox[0], bbox[3], bbox[2]) :
  1308. new OpenLayers.Bounds(bbox[0], bbox[1], bbox[2], bbox[3]);
  1309. };
  1310. /**
  1311. * APIFunction: fromSize
  1312. * Alternative constructor that builds a new OpenLayers.Bounds
  1313. * from a size
  1314. *
  1315. * Parameters:
  1316. * size - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
  1317. * a 'w' and 'h' properties.
  1318. *
  1319. * Returns:
  1320. * {<OpenLayers.Bounds>} New bounds object built from the passed-in size.
  1321. */
  1322. OpenLayers.Bounds.fromSize = function(size) {
  1323. return new OpenLayers.Bounds(0,
  1324. size.h,
  1325. size.w,
  1326. 0);
  1327. };
  1328. /**
  1329. * Function: oppositeQuadrant
  1330. * Get the opposite quadrant for a given quadrant string.
  1331. *
  1332. * Parameters:
  1333. * quadrant - {String} two character quadrant shortstring
  1334. *
  1335. * Returns:
  1336. * {String} The opposing quadrant ("br" "tr" "tl" "bl"). For Example, if
  1337. * you pass in "bl" it returns "tr", if you pass in "br" it
  1338. * returns "tl", etc.
  1339. */
  1340. OpenLayers.Bounds.oppositeQuadrant = function(quadrant) {
  1341. var opp = "";
  1342. opp += (quadrant.charAt(0) == 't') ? 'b' : 't';
  1343. opp += (quadrant.charAt(1) == 'l') ? 'r' : 'l';
  1344. return opp;
  1345. };
  1346. /* ======================================================================
  1347. OpenLayers/BaseTypes/Element.js
  1348. ====================================================================== */
  1349. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  1350. * full list of contributors). Published under the 2-clause BSD license.
  1351. * See license.txt in the OpenLayers distribution or repository for the
  1352. * full text of the license. */
  1353. /**
  1354. * @requires OpenLayers/Util.js
  1355. * @requires OpenLayers/BaseTypes.js
  1356. */
  1357. /**
  1358. * Namespace: OpenLayers.Element
  1359. */
  1360. OpenLayers.Element = {
  1361. /**
  1362. * APIFunction: visible
  1363. *
  1364. * Parameters:
  1365. * element - {DOMElement}
  1366. *
  1367. * Returns:
  1368. * {Boolean} Is the element visible?
  1369. */
  1370. visible: function(element) {
  1371. return OpenLayers.Util.getElement(element).style.display != 'none';
  1372. },
  1373. /**
  1374. * APIFunction: toggle
  1375. * Toggle the visibility of element(s) passed in
  1376. *
  1377. * Parameters:
  1378. * element - {DOMElement} Actually user can pass any number of elements
  1379. */
  1380. toggle: function() {
  1381. for (var i=0, len=arguments.length; i<len; i++) {
  1382. var element = OpenLayers.Util.getElement(arguments[i]);
  1383. var display = OpenLayers.Element.visible(element) ? 'none'
  1384. : '';
  1385. element.style.display = display;
  1386. }
  1387. },
  1388. /**
  1389. * APIFunction: remove
  1390. * Remove the specified element from the DOM.
  1391. *
  1392. * Parameters:
  1393. * element - {DOMElement}
  1394. */
  1395. remove: function(element) {
  1396. element = OpenLayers.Util.getElement(element);
  1397. element.parentNode.removeChild(element);
  1398. },
  1399. /**
  1400. * APIFunction: getHeight
  1401. *
  1402. * Parameters:
  1403. * element - {DOMElement}
  1404. *
  1405. * Returns:
  1406. * {Integer} The offset height of the element passed in
  1407. */
  1408. getHeight: function(element) {
  1409. element = OpenLayers.Util.getElement(element);
  1410. return element.offsetHeight;
  1411. },
  1412. /**
  1413. * Function: hasClass
  1414. * Tests if an element has the given CSS class name.
  1415. *
  1416. * Parameters:
  1417. * element - {DOMElement} A DOM element node.
  1418. * name - {String} The CSS class name to search for.
  1419. *
  1420. * Returns:
  1421. * {Boolean} The element has the given class name.
  1422. */
  1423. hasClass: function(element, name) {
  1424. var names = element.className;
  1425. return (!!names && new RegExp("(^|\\s)" + name + "(\\s|$)").test(names));
  1426. },
  1427. /**
  1428. * Function: addClass
  1429. * Add a CSS class name to an element. Safe where element already has
  1430. * the class name.
  1431. *
  1432. * Parameters:
  1433. * element - {DOMElement} A DOM element node.
  1434. * name - {String} The CSS class name to add.
  1435. *
  1436. * Returns:
  1437. * {DOMElement} The element.
  1438. */
  1439. addClass: function(element, name) {
  1440. if(!OpenLayers.Element.hasClass(element, name)) {
  1441. element.className += (element.className ? " " : "") + name;
  1442. }
  1443. return element;
  1444. },
  1445. /**
  1446. * Function: removeClass
  1447. * Remove a CSS class name from an element. Safe where element does not
  1448. * have the class name.
  1449. *
  1450. * Parameters:
  1451. * element - {DOMElement} A DOM element node.
  1452. * name - {String} The CSS class name to remove.
  1453. *
  1454. * Returns:
  1455. * {DOMElement} The element.
  1456. */
  1457. removeClass: function(element, name) {
  1458. var names = element.className;
  1459. if(names) {
  1460. element.className = OpenLayers.String.trim(
  1461. names.replace(
  1462. new RegExp("(^|\\s+)" + name + "(\\s+|$)"), " "
  1463. )
  1464. );
  1465. }
  1466. return element;
  1467. },
  1468. /**
  1469. * Function: toggleClass
  1470. * Remove a CSS class name from an element if it exists. Add the class name
  1471. * if it doesn't exist.
  1472. *
  1473. * Parameters:
  1474. * element - {DOMElement} A DOM element node.
  1475. * name - {String} The CSS class name to toggle.
  1476. *
  1477. * Returns:
  1478. * {DOMElement} The element.
  1479. */
  1480. toggleClass: function(element, name) {
  1481. if(OpenLayers.Element.hasClass(element, name)) {
  1482. OpenLayers.Element.removeClass(element, name);
  1483. } else {
  1484. OpenLayers.Element.addClass(element, name);
  1485. }
  1486. return element;
  1487. },
  1488. /**
  1489. * APIFunction: getStyle
  1490. *
  1491. * Parameters:
  1492. * element - {DOMElement}
  1493. * style - {?}
  1494. *
  1495. * Returns:
  1496. * {?}
  1497. */
  1498. getStyle: function(element, style) {
  1499. element = OpenLayers.Util.getElement(element);
  1500. var value = null;
  1501. if (element && element.style) {
  1502. value = element.style[OpenLayers.String.camelize(style)];
  1503. if (!value) {
  1504. if (document.defaultView &&
  1505. document.defaultView.getComputedStyle) {
  1506. var css = document.defaultView.getComputedStyle(element, null);
  1507. value = css ? css.getPropertyValue(style) : null;
  1508. } else if (element.currentStyle) {
  1509. value = element.currentStyle[OpenLayers.String.camelize(style)];
  1510. }
  1511. }
  1512. var positions = ['left', 'top', 'right', 'bottom'];
  1513. if (window.opera &&
  1514. (OpenLayers.Util.indexOf(positions,style) != -1) &&
  1515. (OpenLayers.Element.getStyle(element, 'position') == 'static')) {
  1516. value = 'auto';
  1517. }
  1518. }
  1519. return value == 'auto' ? null : value;
  1520. }
  1521. };
  1522. /* ======================================================================
  1523. OpenLayers/BaseTypes/LonLat.js
  1524. ====================================================================== */
  1525. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  1526. * full list of contributors). Published under the 2-clause BSD license.
  1527. * See license.txt in the OpenLayers distribution or repository for the
  1528. * full text of the license. */
  1529. /**
  1530. * @requires OpenLayers/BaseTypes/Class.js
  1531. */
  1532. /**
  1533. * Class: OpenLayers.LonLat
  1534. * This class represents a longitude and latitude pair
  1535. */
  1536. OpenLayers.LonLat = OpenLayers.Class({
  1537. /**
  1538. * APIProperty: lon
  1539. * {Float} The x-axis coodinate in map units
  1540. */
  1541. lon: 0.0,
  1542. /**
  1543. * APIProperty: lat
  1544. * {Float} The y-axis coordinate in map units
  1545. */
  1546. lat: 0.0,
  1547. /**
  1548. * Constructor: OpenLayers.LonLat
  1549. * Create a new map location. Coordinates can be passed either as two
  1550. * arguments, or as a single argument.
  1551. *
  1552. * Parameters (two arguments):
  1553. * lon - {Number} The x-axis coordinate in map units. If your map is in
  1554. * a geographic projection, this will be the Longitude. Otherwise,
  1555. * it will be the x coordinate of the map location in your map units.
  1556. * lat - {Number} The y-axis coordinate in map units. If your map is in
  1557. * a geographic projection, this will be the Latitude. Otherwise,
  1558. * it will be the y coordinate of the map location in your map units.
  1559. *
  1560. * Parameters (single argument):
  1561. * location - {Array(Float)} [lon, lat]
  1562. */
  1563. initialize: function(lon, lat) {
  1564. if (OpenLayers.Util.isArray(lon)) {
  1565. lat = lon[1];
  1566. lon = lon[0];
  1567. }
  1568. this.lon = OpenLayers.Util.toFloat(lon);
  1569. this.lat = OpenLayers.Util.toFloat(lat);
  1570. },
  1571. /**
  1572. * Method: toString
  1573. * Return a readable string version of the lonlat
  1574. *
  1575. * Returns:
  1576. * {String} String representation of OpenLayers.LonLat object.
  1577. * (e.g. <i>"lon=5,lat=42"</i>)
  1578. */
  1579. toString:function() {
  1580. return ("lon=" + this.lon + ",lat=" + this.lat);
  1581. },
  1582. /**
  1583. * APIMethod: toShortString
  1584. *
  1585. * Returns:
  1586. * {String} Shortened String representation of OpenLayers.LonLat object.
  1587. * (e.g. <i>"5, 42"</i>)
  1588. */
  1589. toShortString:function() {
  1590. return (this.lon + ", " + this.lat);
  1591. },
  1592. /**
  1593. * APIMethod: clone
  1594. *
  1595. * Returns:
  1596. * {<OpenLayers.LonLat>} New OpenLayers.LonLat object with the same lon
  1597. * and lat values
  1598. */
  1599. clone:function() {
  1600. return new OpenLayers.LonLat(this.lon, this.lat);
  1601. },
  1602. /**
  1603. * APIMethod: add
  1604. *
  1605. * Parameters:
  1606. * lon - {Float}
  1607. * lat - {Float}
  1608. *
  1609. * Returns:
  1610. * {<OpenLayers.LonLat>} A new OpenLayers.LonLat object with the lon and
  1611. * lat passed-in added to this's.
  1612. */
  1613. add:function(lon, lat) {
  1614. if ( (lon == null) || (lat == null) ) {
  1615. throw new TypeError('LonLat.add cannot receive null values');
  1616. }
  1617. return new OpenLayers.LonLat(this.lon + OpenLayers.Util.toFloat(lon),
  1618. this.lat + OpenLayers.Util.toFloat(lat));
  1619. },
  1620. /**
  1621. * APIMethod: equals
  1622. *
  1623. * Parameters:
  1624. * ll - {<OpenLayers.LonLat>}
  1625. *
  1626. * Returns:
  1627. * {Boolean} Boolean value indicating whether the passed-in
  1628. * <OpenLayers.LonLat> object has the same lon and lat
  1629. * components as this.
  1630. * Note: if ll passed in is null, returns false
  1631. */
  1632. equals:function(ll) {
  1633. var equals = false;
  1634. if (ll != null) {
  1635. equals = ((this.lon == ll.lon && this.lat == ll.lat) ||
  1636. (isNaN(this.lon) && isNaN(this.lat) && isNaN(ll.lon) && isNaN(ll.lat)));
  1637. }
  1638. return equals;
  1639. },
  1640. /**
  1641. * APIMethod: transform
  1642. * Transform the LonLat object from source to dest. This transformation is
  1643. * *in place*: if you want a *new* lonlat, use .clone() first.
  1644. *
  1645. * Parameters:
  1646. * source - {<OpenLayers.Projection>} Source projection.
  1647. * dest - {<OpenLayers.Projection>} Destination projection.
  1648. *
  1649. * Returns:
  1650. * {<OpenLayers.LonLat>} Itself, for use in chaining operations.
  1651. */
  1652. transform: function(source, dest) {
  1653. var point = OpenLayers.Projection.transform(
  1654. {'x': this.lon, 'y': this.lat}, source, dest);
  1655. this.lon = point.x;
  1656. this.lat = point.y;
  1657. return this;
  1658. },
  1659. /**
  1660. * APIMethod: wrapDateLine
  1661. *
  1662. * Parameters:
  1663. * maxExtent - {<OpenLayers.Bounds>}
  1664. *
  1665. * Returns:
  1666. * {<OpenLayers.LonLat>} A copy of this lonlat, but wrapped around the
  1667. * "dateline" (as specified by the borders of
  1668. * maxExtent)
  1669. */
  1670. wrapDateLine: function(maxExtent) {
  1671. var newLonLat = this.clone();
  1672. if (maxExtent) {
  1673. //shift right?
  1674. while (newLonLat.lon < maxExtent.left) {
  1675. newLonLat.lon += maxExtent.getWidth();
  1676. }
  1677. //shift left?
  1678. while (newLonLat.lon > maxExtent.right) {
  1679. newLonLat.lon -= maxExtent.getWidth();
  1680. }
  1681. }
  1682. return newLonLat;
  1683. },
  1684. CLASS_NAME: "OpenLayers.LonLat"
  1685. });
  1686. /**
  1687. * Function: fromString
  1688. * Alternative constructor that builds a new <OpenLayers.LonLat> from a
  1689. * parameter string
  1690. *
  1691. * Parameters:
  1692. * str - {String} Comma-separated Lon,Lat coordinate string.
  1693. * (e.g. <i>"5,40"</i>)
  1694. *
  1695. * Returns:
  1696. * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
  1697. * passed-in String.
  1698. */
  1699. OpenLayers.LonLat.fromString = function(str) {
  1700. var pair = str.split(",");
  1701. return new OpenLayers.LonLat(pair[0], pair[1]);
  1702. };
  1703. /**
  1704. * Function: fromArray
  1705. * Alternative constructor that builds a new <OpenLayers.LonLat> from an
  1706. * array of two numbers that represent lon- and lat-values.
  1707. *
  1708. * Parameters:
  1709. * arr - {Array(Float)} Array of lon/lat values (e.g. [5,-42])
  1710. *
  1711. * Returns:
  1712. * {<OpenLayers.LonLat>} New <OpenLayers.LonLat> object built from the
  1713. * passed-in array.
  1714. */
  1715. OpenLayers.LonLat.fromArray = function(arr) {
  1716. var gotArr = OpenLayers.Util.isArray(arr),
  1717. lon = gotArr && arr[0],
  1718. lat = gotArr && arr[1];
  1719. return new OpenLayers.LonLat(lon, lat);
  1720. };
  1721. /* ======================================================================
  1722. OpenLayers/BaseTypes/Pixel.js
  1723. ====================================================================== */
  1724. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  1725. * full list of contributors). Published under the 2-clause BSD license.
  1726. * See license.txt in the OpenLayers distribution or repository for the
  1727. * full text of the license. */
  1728. /**
  1729. * @requires OpenLayers/BaseTypes/Class.js
  1730. */
  1731. /**
  1732. * Class: OpenLayers.Pixel
  1733. * This class represents a screen coordinate, in x and y coordinates
  1734. */
  1735. OpenLayers.Pixel = OpenLayers.Class({
  1736. /**
  1737. * APIProperty: x
  1738. * {Number} The x coordinate
  1739. */
  1740. x: 0.0,
  1741. /**
  1742. * APIProperty: y
  1743. * {Number} The y coordinate
  1744. */
  1745. y: 0.0,
  1746. /**
  1747. * Constructor: OpenLayers.Pixel
  1748. * Create a new OpenLayers.Pixel instance
  1749. *
  1750. * Parameters:
  1751. * x - {Number} The x coordinate
  1752. * y - {Number} The y coordinate
  1753. *
  1754. * Returns:
  1755. * An instance of OpenLayers.Pixel
  1756. */
  1757. initialize: function(x, y) {
  1758. this.x = parseFloat(x);
  1759. this.y = parseFloat(y);
  1760. },
  1761. /**
  1762. * Method: toString
  1763. * Cast this object into a string
  1764. *
  1765. * Returns:
  1766. * {String} The string representation of Pixel. ex: "x=200.4,y=242.2"
  1767. */
  1768. toString:function() {
  1769. return ("x=" + this.x + ",y=" + this.y);
  1770. },
  1771. /**
  1772. * APIMethod: clone
  1773. * Return a clone of this pixel object
  1774. *
  1775. * Returns:
  1776. * {<OpenLayers.Pixel>} A clone pixel
  1777. */
  1778. clone:function() {
  1779. return new OpenLayers.Pixel(this.x, this.y);
  1780. },
  1781. /**
  1782. * APIMethod: equals
  1783. * Determine whether one pixel is equivalent to another
  1784. *
  1785. * Parameters:
  1786. * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
  1787. * a 'x' and 'y' properties.
  1788. *
  1789. * Returns:
  1790. * {Boolean} The point passed in as parameter is equal to this. Note that
  1791. * if px passed in is null, returns false.
  1792. */
  1793. equals:function(px) {
  1794. var equals = false;
  1795. if (px != null) {
  1796. equals = ((this.x == px.x && this.y == px.y) ||
  1797. (isNaN(this.x) && isNaN(this.y) && isNaN(px.x) && isNaN(px.y)));
  1798. }
  1799. return equals;
  1800. },
  1801. /**
  1802. * APIMethod: distanceTo
  1803. * Returns the distance to the pixel point passed in as a parameter.
  1804. *
  1805. * Parameters:
  1806. * px - {<OpenLayers.Pixel>}
  1807. *
  1808. * Returns:
  1809. * {Float} The pixel point passed in as parameter to calculate the
  1810. * distance to.
  1811. */
  1812. distanceTo:function(px) {
  1813. return Math.sqrt(
  1814. Math.pow(this.x - px.x, 2) +
  1815. Math.pow(this.y - px.y, 2)
  1816. );
  1817. },
  1818. /**
  1819. * APIMethod: add
  1820. *
  1821. * Parameters:
  1822. * x - {Integer}
  1823. * y - {Integer}
  1824. *
  1825. * Returns:
  1826. * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
  1827. * values passed in.
  1828. */
  1829. add:function(x, y) {
  1830. if ( (x == null) || (y == null) ) {
  1831. throw new TypeError('Pixel.add cannot receive null values');
  1832. }
  1833. return new OpenLayers.Pixel(this.x + x, this.y + y);
  1834. },
  1835. /**
  1836. * APIMethod: offset
  1837. *
  1838. * Parameters
  1839. * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
  1840. * a 'x' and 'y' properties.
  1841. *
  1842. * Returns:
  1843. * {<OpenLayers.Pixel>} A new Pixel with this pixel's x&y augmented by the
  1844. * x&y values of the pixel passed in.
  1845. */
  1846. offset:function(px) {
  1847. var newPx = this.clone();
  1848. if (px) {
  1849. newPx = this.add(px.x, px.y);
  1850. }
  1851. return newPx;
  1852. },
  1853. CLASS_NAME: "OpenLayers.Pixel"
  1854. });
  1855. /* ======================================================================
  1856. OpenLayers/BaseTypes/Size.js
  1857. ====================================================================== */
  1858. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  1859. * full list of contributors). Published under the 2-clause BSD license.
  1860. * See license.txt in the OpenLayers distribution or repository for the
  1861. * full text of the license. */
  1862. /**
  1863. * @requires OpenLayers/BaseTypes/Class.js
  1864. */
  1865. /**
  1866. * Class: OpenLayers.Size
  1867. * Instances of this class represent a width/height pair
  1868. */
  1869. OpenLayers.Size = OpenLayers.Class({
  1870. /**
  1871. * APIProperty: w
  1872. * {Number} width
  1873. */
  1874. w: 0.0,
  1875. /**
  1876. * APIProperty: h
  1877. * {Number} height
  1878. */
  1879. h: 0.0,
  1880. /**
  1881. * Constructor: OpenLayers.Size
  1882. * Create an instance of OpenLayers.Size
  1883. *
  1884. * Parameters:
  1885. * w - {Number} width
  1886. * h - {Number} height
  1887. */
  1888. initialize: function(w, h) {
  1889. this.w = parseFloat(w);
  1890. this.h = parseFloat(h);
  1891. },
  1892. /**
  1893. * Method: toString
  1894. * Return the string representation of a size object
  1895. *
  1896. * Returns:
  1897. * {String} The string representation of OpenLayers.Size object.
  1898. * (e.g. <i>"w=55,h=66"</i>)
  1899. */
  1900. toString:function() {
  1901. return ("w=" + this.w + ",h=" + this.h);
  1902. },
  1903. /**
  1904. * APIMethod: clone
  1905. * Create a clone of this size object
  1906. *
  1907. * Returns:
  1908. * {<OpenLayers.Size>} A new OpenLayers.Size object with the same w and h
  1909. * values
  1910. */
  1911. clone:function() {
  1912. return new OpenLayers.Size(this.w, this.h);
  1913. },
  1914. /**
  1915. *
  1916. * APIMethod: equals
  1917. * Determine where this size is equal to another
  1918. *
  1919. * Parameters:
  1920. * sz - {<OpenLayers.Size>|Object} An OpenLayers.Size or an object with
  1921. * a 'w' and 'h' properties.
  1922. *
  1923. * Returns:
  1924. * {Boolean} The passed in size has the same h and w properties as this one.
  1925. * Note that if sz passed in is null, returns false.
  1926. */
  1927. equals:function(sz) {
  1928. var equals = false;
  1929. if (sz != null) {
  1930. equals = ((this.w == sz.w && this.h == sz.h) ||
  1931. (isNaN(this.w) && isNaN(this.h) && isNaN(sz.w) && isNaN(sz.h)));
  1932. }
  1933. return equals;
  1934. },
  1935. CLASS_NAME: "OpenLayers.Size"
  1936. });
  1937. /* ======================================================================
  1938. OpenLayers/Console.js
  1939. ====================================================================== */
  1940. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  1941. * full list of contributors). Published under the 2-clause BSD license.
  1942. * See license.txt in the OpenLayers distribution or repository for the
  1943. * full text of the license. */
  1944. /**
  1945. * @requires OpenLayers/BaseTypes/Class.js
  1946. */
  1947. /**
  1948. * Namespace: OpenLayers.Console
  1949. * The OpenLayers.Console namespace is used for debugging and error logging.
  1950. * If the Firebug Lite (../Firebug/firebug.js) is included before this script,
  1951. * calls to OpenLayers.Console methods will get redirected to window.console.
  1952. * This makes use of the Firebug extension where available and allows for
  1953. * cross-browser debugging Firebug style.
  1954. *
  1955. * Note:
  1956. * Note that behavior will differ with the Firebug extention and Firebug Lite.
  1957. * Most notably, the Firebug Lite console does not currently allow for
  1958. * hyperlinks to code or for clicking on object to explore their properties.
  1959. *
  1960. */
  1961. OpenLayers.Console = {
  1962. /**
  1963. * Create empty functions for all console methods. The real value of these
  1964. * properties will be set if Firebug Lite (../Firebug/firebug.js script) is
  1965. * included. We explicitly require the Firebug Lite script to trigger
  1966. * functionality of the OpenLayers.Console methods.
  1967. */
  1968. /**
  1969. * APIFunction: log
  1970. * Log an object in the console. The Firebug Lite console logs string
  1971. * representation of objects. Given multiple arguments, they will
  1972. * be cast to strings and logged with a space delimiter. If the first
  1973. * argument is a string with printf-like formatting, subsequent arguments
  1974. * will be used in string substitution. Any additional arguments (beyond
  1975. * the number substituted in a format string) will be appended in a space-
  1976. * delimited line.
  1977. *
  1978. * Parameters:
  1979. * object - {Object}
  1980. */
  1981. log: function() {},
  1982. /**
  1983. * APIFunction: debug
  1984. * Writes a message to the console, including a hyperlink to the line
  1985. * where it was called.
  1986. *
  1987. * May be called with multiple arguments as with OpenLayers.Console.log().
  1988. *
  1989. * Parameters:
  1990. * object - {Object}
  1991. */
  1992. debug: function() {},
  1993. /**
  1994. * APIFunction: info
  1995. * Writes a message to the console with the visual "info" icon and color
  1996. * coding and a hyperlink to the line where it was called.
  1997. *
  1998. * May be called with multiple arguments as with OpenLayers.Console.log().
  1999. *
  2000. * Parameters:
  2001. * object - {Object}
  2002. */
  2003. info: function() {},
  2004. /**
  2005. * APIFunction: warn
  2006. * Writes a message to the console with the visual "warning" icon and
  2007. * color coding and a hyperlink to the line where it was called.
  2008. *
  2009. * May be called with multiple arguments as with OpenLayers.Console.log().
  2010. *
  2011. * Parameters:
  2012. * object - {Object}
  2013. */
  2014. warn: function() {},
  2015. /**
  2016. * APIFunction: error
  2017. * Writes a message to the console with the visual "error" icon and color
  2018. * coding and a hyperlink to the line where it was called.
  2019. *
  2020. * May be called with multiple arguments as with OpenLayers.Console.log().
  2021. *
  2022. * Parameters:
  2023. * object - {Object}
  2024. */
  2025. error: function() {},
  2026. /**
  2027. * APIFunction: userError
  2028. * A single interface for showing error messages to the user. The default
  2029. * behavior is a Javascript alert, though this can be overridden by
  2030. * reassigning OpenLayers.Console.userError to a different function.
  2031. *
  2032. * Expects a single error message
  2033. *
  2034. * Parameters:
  2035. * error - {Object}
  2036. */
  2037. userError: function(error) {
  2038. alert(error);
  2039. },
  2040. /**
  2041. * APIFunction: assert
  2042. * Tests that an expression is true. If not, it will write a message to
  2043. * the console and throw an exception.
  2044. *
  2045. * May be called with multiple arguments as with OpenLayers.Console.log().
  2046. *
  2047. * Parameters:
  2048. * object - {Object}
  2049. */
  2050. assert: function() {},
  2051. /**
  2052. * APIFunction: dir
  2053. * Prints an interactive listing of all properties of the object. This
  2054. * looks identical to the view that you would see in the DOM tab.
  2055. *
  2056. * Parameters:
  2057. * object - {Object}
  2058. */
  2059. dir: function() {},
  2060. /**
  2061. * APIFunction: dirxml
  2062. * Prints the XML source tree of an HTML or XML element. This looks
  2063. * identical to the view that you would see in the HTML tab. You can click
  2064. * on any node to inspect it in the HTML tab.
  2065. *
  2066. * Parameters:
  2067. * object - {Object}
  2068. */
  2069. dirxml: function() {},
  2070. /**
  2071. * APIFunction: trace
  2072. * Prints an interactive stack trace of JavaScript execution at the point
  2073. * where it is called. The stack trace details the functions on the stack,
  2074. * as well as the values that were passed as arguments to each function.
  2075. * You can click each function to take you to its source in the Script tab,
  2076. * and click each argument value to inspect it in the DOM or HTML tabs.
  2077. *
  2078. */
  2079. trace: function() {},
  2080. /**
  2081. * APIFunction: group
  2082. * Writes a message to the console and opens a nested block to indent all
  2083. * future messages sent to the console. Call OpenLayers.Console.groupEnd()
  2084. * to close the block.
  2085. *
  2086. * May be called with multiple arguments as with OpenLayers.Console.log().
  2087. *
  2088. * Parameters:
  2089. * object - {Object}
  2090. */
  2091. group: function() {},
  2092. /**
  2093. * APIFunction: groupEnd
  2094. * Closes the most recently opened block created by a call to
  2095. * OpenLayers.Console.group
  2096. */
  2097. groupEnd: function() {},
  2098. /**
  2099. * APIFunction: time
  2100. * Creates a new timer under the given name. Call
  2101. * OpenLayers.Console.timeEnd(name)
  2102. * with the same name to stop the timer and print the time elapsed.
  2103. *
  2104. * Parameters:
  2105. * name - {String}
  2106. */
  2107. time: function() {},
  2108. /**
  2109. * APIFunction: timeEnd
  2110. * Stops a timer created by a call to OpenLayers.Console.time(name) and
  2111. * writes the time elapsed.
  2112. *
  2113. * Parameters:
  2114. * name - {String}
  2115. */
  2116. timeEnd: function() {},
  2117. /**
  2118. * APIFunction: profile
  2119. * Turns on the JavaScript profiler. The optional argument title would
  2120. * contain the text to be printed in the header of the profile report.
  2121. *
  2122. * This function is not currently implemented in Firebug Lite.
  2123. *
  2124. * Parameters:
  2125. * title - {String} Optional title for the profiler
  2126. */
  2127. profile: function() {},
  2128. /**
  2129. * APIFunction: profileEnd
  2130. * Turns off the JavaScript profiler and prints its report.
  2131. *
  2132. * This function is not currently implemented in Firebug Lite.
  2133. */
  2134. profileEnd: function() {},
  2135. /**
  2136. * APIFunction: count
  2137. * Writes the number of times that the line of code where count was called
  2138. * was executed. The optional argument title will print a message in
  2139. * addition to the number of the count.
  2140. *
  2141. * This function is not currently implemented in Firebug Lite.
  2142. *
  2143. * Parameters:
  2144. * title - {String} Optional title to be printed with count
  2145. */
  2146. count: function() {},
  2147. CLASS_NAME: "OpenLayers.Console"
  2148. };
  2149. /**
  2150. * Execute an anonymous function to extend the OpenLayers.Console namespace
  2151. * if the firebug.js script is included. This closure is used so that the
  2152. * "scripts" and "i" variables don't pollute the global namespace.
  2153. */
  2154. (function() {
  2155. /**
  2156. * If Firebug Lite is included (before this script), re-route all
  2157. * OpenLayers.Console calls to the console object.
  2158. */
  2159. var scripts = document.getElementsByTagName("script");
  2160. for(var i=0, len=scripts.length; i<len; ++i) {
  2161. if(scripts[i].src.indexOf("firebug.js") != -1) {
  2162. if(console) {
  2163. OpenLayers.Util.extend(OpenLayers.Console, console);
  2164. break;
  2165. }
  2166. }
  2167. }
  2168. })();
  2169. /* ======================================================================
  2170. OpenLayers/Lang.js
  2171. ====================================================================== */
  2172. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  2173. * full list of contributors). Published under the 2-clause BSD license.
  2174. * See license.txt in the OpenLayers distribution or repository for the
  2175. * full text of the license. */
  2176. /**
  2177. * @requires OpenLayers/BaseTypes.js
  2178. * @requires OpenLayers/Console.js
  2179. */
  2180. /**
  2181. * Namespace: OpenLayers.Lang
  2182. * Internationalization namespace. Contains dictionaries in various languages
  2183. * and methods to set and get the current language.
  2184. */
  2185. OpenLayers.Lang = {
  2186. /**
  2187. * Property: code
  2188. * {String} Current language code to use in OpenLayers. Use the
  2189. * <setCode> method to set this value and the <getCode> method to
  2190. * retrieve it.
  2191. */
  2192. code: null,
  2193. /**
  2194. * APIProperty: defaultCode
  2195. * {String} Default language to use when a specific language can't be
  2196. * found. Default is "en".
  2197. */
  2198. defaultCode: "en",
  2199. /**
  2200. * APIFunction: getCode
  2201. * Get the current language code.
  2202. *
  2203. * Returns:
  2204. * {String} The current language code.
  2205. */
  2206. getCode: function() {
  2207. if(!OpenLayers.Lang.code) {
  2208. OpenLayers.Lang.setCode();
  2209. }
  2210. return OpenLayers.Lang.code;
  2211. },
  2212. /**
  2213. * APIFunction: setCode
  2214. * Set the language code for string translation. This code is used by
  2215. * the <OpenLayers.Lang.translate> method.
  2216. *
  2217. * Parameters:
  2218. * code - {String} These codes follow the IETF recommendations at
  2219. * http://www.ietf.org/rfc/rfc3066.txt. If no value is set, the
  2220. * browser's language setting will be tested. If no <OpenLayers.Lang>
  2221. * dictionary exists for the code, the <OpenLayers.String.defaultLang>
  2222. * will be used.
  2223. */
  2224. setCode: function(code) {
  2225. var lang;
  2226. if(!code) {
  2227. code = (OpenLayers.BROWSER_NAME == "msie") ?
  2228. navigator.userLanguage : navigator.language;
  2229. }
  2230. var parts = code.split('-');
  2231. parts[0] = parts[0].toLowerCase();
  2232. if(typeof OpenLayers.Lang[parts[0]] == "object") {
  2233. lang = parts[0];
  2234. }
  2235. // check for regional extensions
  2236. if(parts[1]) {
  2237. var testLang = parts[0] + '-' + parts[1].toUpperCase();
  2238. if(typeof OpenLayers.Lang[testLang] == "object") {
  2239. lang = testLang;
  2240. }
  2241. }
  2242. if(!lang) {
  2243. OpenLayers.Console.warn(
  2244. 'Failed to find OpenLayers.Lang.' + parts.join("-") +
  2245. ' dictionary, falling back to default language'
  2246. );
  2247. lang = OpenLayers.Lang.defaultCode;
  2248. }
  2249. OpenLayers.Lang.code = lang;
  2250. },
  2251. /**
  2252. * APIMethod: translate
  2253. * Looks up a key from a dictionary based on the current language string.
  2254. * The value of <getCode> will be used to determine the appropriate
  2255. * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
  2256. *
  2257. * Parameters:
  2258. * key - {String} The key for an i18n string value in the dictionary.
  2259. * context - {Object} Optional context to be used with
  2260. * <OpenLayers.String.format>.
  2261. *
  2262. * Returns:
  2263. * {String} A internationalized string.
  2264. */
  2265. translate: function(key, context) {
  2266. var dictionary = OpenLayers.Lang[OpenLayers.Lang.getCode()];
  2267. var message = dictionary && dictionary[key];
  2268. if(!message) {
  2269. // Message not found, fall back to message key
  2270. message = key;
  2271. }
  2272. if(context) {
  2273. message = OpenLayers.String.format(message, context);
  2274. }
  2275. return message;
  2276. }
  2277. };
  2278. /**
  2279. * APIMethod: OpenLayers.i18n
  2280. * Alias for <OpenLayers.Lang.translate>. Looks up a key from a dictionary
  2281. * based on the current language string. The value of
  2282. * <OpenLayers.Lang.getCode> will be used to determine the appropriate
  2283. * dictionary. Dictionaries are stored in <OpenLayers.Lang>.
  2284. *
  2285. * Parameters:
  2286. * key - {String} The key for an i18n string value in the dictionary.
  2287. * context - {Object} Optional context to be used with
  2288. * <OpenLayers.String.format>.
  2289. *
  2290. * Returns:
  2291. * {String} A internationalized string.
  2292. */
  2293. OpenLayers.i18n = OpenLayers.Lang.translate;
  2294. /* ======================================================================
  2295. OpenLayers/Util.js
  2296. ====================================================================== */
  2297. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  2298. * full list of contributors). Published under the 2-clause BSD license.
  2299. * See license.txt in the OpenLayers distribution or repository for the
  2300. * full text of the license. */
  2301. /**
  2302. * @requires OpenLayers/BaseTypes.js
  2303. * @requires OpenLayers/BaseTypes/Bounds.js
  2304. * @requires OpenLayers/BaseTypes/Element.js
  2305. * @requires OpenLayers/BaseTypes/LonLat.js
  2306. * @requires OpenLayers/BaseTypes/Pixel.js
  2307. * @requires OpenLayers/BaseTypes/Size.js
  2308. * @requires OpenLayers/Lang.js
  2309. */
  2310. /**
  2311. * Namespace: Util
  2312. */
  2313. OpenLayers.Util = OpenLayers.Util || {};
  2314. /**
  2315. * Function: getElement
  2316. * This is the old $() from prototype
  2317. *
  2318. * Parameters:
  2319. * e - {String or DOMElement or Window}
  2320. *
  2321. * Returns:
  2322. * {Array(DOMElement) or DOMElement}
  2323. */
  2324. OpenLayers.Util.getElement = function() {
  2325. var elements = [];
  2326. for (var i=0, len=arguments.length; i<len; i++) {
  2327. var element = arguments[i];
  2328. if (typeof element == 'string') {
  2329. element = document.getElementById(element);
  2330. }
  2331. if (arguments.length == 1) {
  2332. return element;
  2333. }
  2334. elements.push(element);
  2335. }
  2336. return elements;
  2337. };
  2338. /**
  2339. * Function: isElement
  2340. * A cross-browser implementation of "e instanceof Element".
  2341. *
  2342. * Parameters:
  2343. * o - {Object} The object to test.
  2344. *
  2345. * Returns:
  2346. * {Boolean}
  2347. */
  2348. OpenLayers.Util.isElement = function(o) {
  2349. return !!(o && o.nodeType === 1);
  2350. };
  2351. /**
  2352. * Function: isArray
  2353. * Tests that the provided object is an array.
  2354. * This test handles the cross-IFRAME case not caught
  2355. * by "a instanceof Array" and should be used instead.
  2356. *
  2357. * Parameters:
  2358. * a - {Object} the object test.
  2359. *
  2360. * Returns:
  2361. * {Boolean} true if the object is an array.
  2362. */
  2363. OpenLayers.Util.isArray = function(a) {
  2364. return (Object.prototype.toString.call(a) === '[object Array]');
  2365. };
  2366. /**
  2367. * Maintain existing definition of $.
  2368. */
  2369. if(typeof window.$ === "undefined") {
  2370. window.$ = OpenLayers.Util.getElement;
  2371. }
  2372. /**
  2373. * Function: removeItem
  2374. * Remove an object from an array. Iterates through the array
  2375. * to find the item, then removes it.
  2376. *
  2377. * Parameters:
  2378. * array - {Array}
  2379. * item - {Object}
  2380. *
  2381. * Returns:
  2382. * {Array} A reference to the array
  2383. */
  2384. OpenLayers.Util.removeItem = function(array, item) {
  2385. for(var i = array.length - 1; i >= 0; i--) {
  2386. if(array[i] == item) {
  2387. array.splice(i,1);
  2388. //break;more than once??
  2389. }
  2390. }
  2391. return array;
  2392. };
  2393. /**
  2394. * Function: indexOf
  2395. * Seems to exist already in FF, but not in MOZ.
  2396. *
  2397. * Parameters:
  2398. * array - {Array}
  2399. * obj - {*}
  2400. *
  2401. * Returns:
  2402. * {Integer} The index at, which the first object was found in the array.
  2403. * If not found, returns -1.
  2404. */
  2405. OpenLayers.Util.indexOf = function(array, obj) {
  2406. // use the build-in function if available.
  2407. if (typeof array.indexOf == "function") {
  2408. return array.indexOf(obj);
  2409. } else {
  2410. for (var i = 0, len = array.length; i < len; i++) {
  2411. if (array[i] == obj) {
  2412. return i;
  2413. }
  2414. }
  2415. return -1;
  2416. }
  2417. };
  2418. /**
  2419. * Function: modifyDOMElement
  2420. *
  2421. * Modifies many properties of a DOM element all at once. Passing in
  2422. * null to an individual parameter will avoid setting the attribute.
  2423. *
  2424. * Parameters:
  2425. * element - {DOMElement} DOM element to modify.
  2426. * id - {String} The element id attribute to set.
  2427. * px - {<OpenLayers.Pixel>|Object} The element left and top position,
  2428. * OpenLayers.Pixel or an object with
  2429. * a 'x' and 'y' properties.
  2430. * sz - {<OpenLayers.Size>|Object} The element width and height,
  2431. * OpenLayers.Size or an object with a
  2432. * 'w' and 'h' properties.
  2433. * position - {String} The position attribute. eg: absolute,
  2434. * relative, etc.
  2435. * border - {String} The style.border attribute. eg:
  2436. * solid black 2px
  2437. * overflow - {String} The style.overview attribute.
  2438. * opacity - {Float} Fractional value (0.0 - 1.0)
  2439. */
  2440. OpenLayers.Util.modifyDOMElement = function(element, id, px, sz, position,
  2441. border, overflow, opacity) {
  2442. if (id) {
  2443. element.id = id;
  2444. }
  2445. if (px) {
  2446. element.style.left = px.x + "px";
  2447. element.style.top = px.y + "px";
  2448. }
  2449. if (sz) {
  2450. element.style.width = sz.w + "px";
  2451. element.style.height = sz.h + "px";
  2452. }
  2453. if (position) {
  2454. element.style.position = position;
  2455. }
  2456. if (border) {
  2457. element.style.border = border;
  2458. }
  2459. if (overflow) {
  2460. element.style.overflow = overflow;
  2461. }
  2462. if (parseFloat(opacity) >= 0.0 && parseFloat(opacity) < 1.0) {
  2463. element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')';
  2464. element.style.opacity = opacity;
  2465. } else if (parseFloat(opacity) == 1.0) {
  2466. element.style.filter = '';
  2467. element.style.opacity = '';
  2468. }
  2469. };
  2470. /**
  2471. * Function: createDiv
  2472. * Creates a new div and optionally set some standard attributes.
  2473. * Null may be passed to each parameter if you do not wish to
  2474. * set a particular attribute.
  2475. * Note - zIndex is NOT set on the resulting div.
  2476. *
  2477. * Parameters:
  2478. * id - {String} An identifier for this element. If no id is
  2479. * passed an identifier will be created
  2480. * automatically.
  2481. * px - {<OpenLayers.Pixel>|Object} The element left and top position,
  2482. * OpenLayers.Pixel or an object with
  2483. * a 'x' and 'y' properties.
  2484. * sz - {<OpenLayers.Size>|Object} The element width and height,
  2485. * OpenLayers.Size or an object with a
  2486. * 'w' and 'h' properties.
  2487. * imgURL - {String} A url pointing to an image to use as a
  2488. * background image.
  2489. * position - {String} The style.position value. eg: absolute,
  2490. * relative etc.
  2491. * border - {String} The the style.border value.
  2492. * eg: 2px solid black
  2493. * overflow - {String} The style.overflow value. Eg. hidden
  2494. * opacity - {Float} Fractional value (0.0 - 1.0)
  2495. *
  2496. * Returns:
  2497. * {DOMElement} A DOM Div created with the specified attributes.
  2498. */
  2499. OpenLayers.Util.createDiv = function(id, px, sz, imgURL, position,
  2500. border, overflow, opacity) {
  2501. var dom = document.createElement('div');
  2502. if (imgURL) {
  2503. dom.style.backgroundImage = 'url(' + imgURL + ')';
  2504. }
  2505. //set generic properties
  2506. if (!id) {
  2507. id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
  2508. }
  2509. if (!position) {
  2510. position = "absolute";
  2511. }
  2512. OpenLayers.Util.modifyDOMElement(dom, id, px, sz, position,
  2513. border, overflow, opacity);
  2514. return dom;
  2515. };
  2516. /**
  2517. * Function: createImage
  2518. * Creates an img element with specific attribute values.
  2519. *
  2520. * Parameters:
  2521. * id - {String} The id field for the img. If none assigned one will be
  2522. * automatically generated.
  2523. * px - {<OpenLayers.Pixel>|Object} The element left and top position,
  2524. * OpenLayers.Pixel or an object with
  2525. * a 'x' and 'y' properties.
  2526. * sz - {<OpenLayers.Size>|Object} The element width and height,
  2527. * OpenLayers.Size or an object with a
  2528. * 'w' and 'h' properties.
  2529. * imgURL - {String} The url to use as the image source.
  2530. * position - {String} The style.position value.
  2531. * border - {String} The border to place around the image.
  2532. * opacity - {Float} Fractional value (0.0 - 1.0)
  2533. * delayDisplay - {Boolean} If true waits until the image has been
  2534. * loaded.
  2535. *
  2536. * Returns:
  2537. * {DOMElement} A DOM Image created with the specified attributes.
  2538. */
  2539. OpenLayers.Util.createImage = function(id, px, sz, imgURL, position, border,
  2540. opacity, delayDisplay) {
  2541. var image = document.createElement("img");
  2542. //set generic properties
  2543. if (!id) {
  2544. id = OpenLayers.Util.createUniqueID("OpenLayersDiv");
  2545. }
  2546. if (!position) {
  2547. position = "relative";
  2548. }
  2549. OpenLayers.Util.modifyDOMElement(image, id, px, sz, position,
  2550. border, null, opacity);
  2551. if (delayDisplay) {
  2552. image.style.display = "none";
  2553. function display() {
  2554. image.style.display = "";
  2555. OpenLayers.Event.stopObservingElement(image);
  2556. }
  2557. OpenLayers.Event.observe(image, "load", display);
  2558. OpenLayers.Event.observe(image, "error", display);
  2559. }
  2560. //set special properties
  2561. image.style.alt = id;
  2562. image.galleryImg = "no";
  2563. if (imgURL) {
  2564. image.src = imgURL;
  2565. }
  2566. return image;
  2567. };
  2568. /**
  2569. * Property: IMAGE_RELOAD_ATTEMPTS
  2570. * {Integer} How many times should we try to reload an image before giving up?
  2571. * Default is 0
  2572. */
  2573. OpenLayers.IMAGE_RELOAD_ATTEMPTS = 0;
  2574. /**
  2575. * Property: alphaHackNeeded
  2576. * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
  2577. */
  2578. OpenLayers.Util.alphaHackNeeded = null;
  2579. /**
  2580. * Function: alphaHack
  2581. * Checks whether it's necessary (and possible) to use the png alpha
  2582. * hack which allows alpha transparency for png images under Internet
  2583. * Explorer.
  2584. *
  2585. * Returns:
  2586. * {Boolean} true if the png alpha hack is necessary and possible, false otherwise.
  2587. */
  2588. OpenLayers.Util.alphaHack = function() {
  2589. if (OpenLayers.Util.alphaHackNeeded == null) {
  2590. var arVersion = navigator.appVersion.split("MSIE");
  2591. var version = parseFloat(arVersion[1]);
  2592. var filter = false;
  2593. // IEs4Lin dies when trying to access document.body.filters, because
  2594. // the property is there, but requires a DLL that can't be provided. This
  2595. // means that we need to wrap this in a try/catch so that this can
  2596. // continue.
  2597. try {
  2598. filter = !!(document.body.filters);
  2599. } catch (e) {}
  2600. OpenLayers.Util.alphaHackNeeded = (filter &&
  2601. (version >= 5.5) && (version < 7));
  2602. }
  2603. return OpenLayers.Util.alphaHackNeeded;
  2604. };
  2605. /**
  2606. * Function: modifyAlphaImageDiv
  2607. *
  2608. * Parameters:
  2609. * div - {DOMElement} Div containing Alpha-adjusted Image
  2610. * id - {String}
  2611. * px - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
  2612. * a 'x' and 'y' properties.
  2613. * sz - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
  2614. * a 'w' and 'h' properties.
  2615. * imgURL - {String}
  2616. * position - {String}
  2617. * border - {String}
  2618. * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
  2619. * opacity - {Float} Fractional value (0.0 - 1.0)
  2620. */
  2621. OpenLayers.Util.modifyAlphaImageDiv = function(div, id, px, sz, imgURL,
  2622. position, border, sizing,
  2623. opacity) {
  2624. OpenLayers.Util.modifyDOMElement(div, id, px, sz, position,
  2625. null, null, opacity);
  2626. var img = div.childNodes[0];
  2627. if (imgURL) {
  2628. img.src = imgURL;
  2629. }
  2630. OpenLayers.Util.modifyDOMElement(img, div.id + "_innerImage", null, sz,
  2631. "relative", border);
  2632. if (OpenLayers.Util.alphaHack()) {
  2633. if(div.style.display != "none") {
  2634. div.style.display = "inline-block";
  2635. }
  2636. if (sizing == null) {
  2637. sizing = "scale";
  2638. }
  2639. div.style.filter = "progid:DXImageTransform.Microsoft" +
  2640. ".AlphaImageLoader(src='" + img.src + "', " +
  2641. "sizingMethod='" + sizing + "')";
  2642. if (parseFloat(div.style.opacity) >= 0.0 &&
  2643. parseFloat(div.style.opacity) < 1.0) {
  2644. div.style.filter += " alpha(opacity=" + div.style.opacity * 100 + ")";
  2645. }
  2646. img.style.filter = "alpha(opacity=0)";
  2647. }
  2648. };
  2649. /**
  2650. * Function: createAlphaImageDiv
  2651. *
  2652. * Parameters:
  2653. * id - {String}
  2654. * px - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or an object with
  2655. * a 'x' and 'y' properties.
  2656. * sz - {<OpenLayers.Size>|Object} OpenLayers.Size or an object with
  2657. * a 'w' and 'h' properties.
  2658. * imgURL - {String}
  2659. * position - {String}
  2660. * border - {String}
  2661. * sizing - {String} 'crop', 'scale', or 'image'. Default is "scale"
  2662. * opacity - {Float} Fractional value (0.0 - 1.0)
  2663. * delayDisplay - {Boolean} If true waits until the image has been
  2664. * loaded.
  2665. *
  2666. * Returns:
  2667. * {DOMElement} A DOM Div created with a DOM Image inside it. If the hack is
  2668. * needed for transparency in IE, it is added.
  2669. */
  2670. OpenLayers.Util.createAlphaImageDiv = function(id, px, sz, imgURL,
  2671. position, border, sizing,
  2672. opacity, delayDisplay) {
  2673. var div = OpenLayers.Util.createDiv();
  2674. var img = OpenLayers.Util.createImage(null, null, null, null, null, null,
  2675. null, delayDisplay);
  2676. img.className = "olAlphaImg";
  2677. div.appendChild(img);
  2678. OpenLayers.Util.modifyAlphaImageDiv(div, id, px, sz, imgURL, position,
  2679. border, sizing, opacity);
  2680. return div;
  2681. };
  2682. /**
  2683. * Function: upperCaseObject
  2684. * Creates a new hashtable and copies over all the keys from the
  2685. * passed-in object, but storing them under an uppercased
  2686. * version of the key at which they were stored.
  2687. *
  2688. * Parameters:
  2689. * object - {Object}
  2690. *
  2691. * Returns:
  2692. * {Object} A new Object with all the same keys but uppercased
  2693. */
  2694. OpenLayers.Util.upperCaseObject = function (object) {
  2695. var uObject = {};
  2696. for (var key in object) {
  2697. uObject[key.toUpperCase()] = object[key];
  2698. }
  2699. return uObject;
  2700. };
  2701. /**
  2702. * Function: applyDefaults
  2703. * Takes an object and copies any properties that don't exist from
  2704. * another properties, by analogy with OpenLayers.Util.extend() from
  2705. * Prototype.js.
  2706. *
  2707. * Parameters:
  2708. * to - {Object} The destination object.
  2709. * from - {Object} The source object. Any properties of this object that
  2710. * are undefined in the to object will be set on the to object.
  2711. *
  2712. * Returns:
  2713. * {Object} A reference to the to object. Note that the to argument is modified
  2714. * in place and returned by this function.
  2715. */
  2716. OpenLayers.Util.applyDefaults = function (to, from) {
  2717. to = to || {};
  2718. /*
  2719. * FF/Windows < 2.0.0.13 reports "Illegal operation on WrappedNative
  2720. * prototype object" when calling hawOwnProperty if the source object is an
  2721. * instance of window.Event.
  2722. */
  2723. var fromIsEvt = typeof window.Event == "function"
  2724. && from instanceof window.Event;
  2725. for (var key in from) {
  2726. if (to[key] === undefined ||
  2727. (!fromIsEvt && from.hasOwnProperty
  2728. && from.hasOwnProperty(key) && !to.hasOwnProperty(key))) {
  2729. to[key] = from[key];
  2730. }
  2731. }
  2732. /**
  2733. * IE doesn't include the toString property when iterating over an object's
  2734. * properties with the for(property in object) syntax. Explicitly check if
  2735. * the source has its own toString property.
  2736. */
  2737. if(!fromIsEvt && from && from.hasOwnProperty
  2738. && from.hasOwnProperty('toString') && !to.hasOwnProperty('toString')) {
  2739. to.toString = from.toString;
  2740. }
  2741. return to;
  2742. };
  2743. /**
  2744. * Function: getParameterString
  2745. *
  2746. * Parameters:
  2747. * params - {Object}
  2748. *
  2749. * Returns:
  2750. * {String} A concatenation of the properties of an object in
  2751. * http parameter notation.
  2752. * (ex. <i>"key1=value1&key2=value2&key3=value3"</i>)
  2753. * If a parameter is actually a list, that parameter will then
  2754. * be set to a comma-seperated list of values (foo,bar) instead
  2755. * of being URL escaped (foo%3Abar).
  2756. */
  2757. OpenLayers.Util.getParameterString = function(params) {
  2758. var paramsArray = [];
  2759. for (var key in params) {
  2760. var value = params[key];
  2761. if ((value != null) && (typeof value != 'function')) {
  2762. var encodedValue;
  2763. if (typeof value == 'object' && value.constructor == Array) {
  2764. /* value is an array; encode items and separate with "," */
  2765. var encodedItemArray = [];
  2766. var item;
  2767. for (var itemIndex=0, len=value.length; itemIndex<len; itemIndex++) {
  2768. item = value[itemIndex];
  2769. encodedItemArray.push(encodeURIComponent(
  2770. (item === null || item === undefined) ? "" : item)
  2771. );
  2772. }
  2773. encodedValue = encodedItemArray.join(",");
  2774. }
  2775. else {
  2776. /* value is a string; simply encode */
  2777. encodedValue = encodeURIComponent(value);
  2778. }
  2779. paramsArray.push(encodeURIComponent(key) + "=" + encodedValue);
  2780. }
  2781. }
  2782. return paramsArray.join("&");
  2783. };
  2784. /**
  2785. * Function: urlAppend
  2786. * Appends a parameter string to a url. This function includes the logic for
  2787. * using the appropriate character (none, & or ?) to append to the url before
  2788. * appending the param string.
  2789. *
  2790. * Parameters:
  2791. * url - {String} The url to append to
  2792. * paramStr - {String} The param string to append
  2793. *
  2794. * Returns:
  2795. * {String} The new url
  2796. */
  2797. OpenLayers.Util.urlAppend = function(url, paramStr) {
  2798. var newUrl = url;
  2799. if(paramStr) {
  2800. var parts = (url + " ").split(/[?&]/);
  2801. newUrl += (parts.pop() === " " ?
  2802. paramStr :
  2803. parts.length ? "&" + paramStr : "?" + paramStr);
  2804. }
  2805. return newUrl;
  2806. };
  2807. /**
  2808. * Function: getImagesLocation
  2809. *
  2810. * Returns:
  2811. * {String} The fully formatted image location string
  2812. */
  2813. OpenLayers.Util.getImagesLocation = function() {
  2814. return OpenLayers.ImgPath || (OpenLayers._getScriptLocation() + "img/");
  2815. };
  2816. /**
  2817. * Function: getImageLocation
  2818. *
  2819. * Returns:
  2820. * {String} The fully formatted location string for a specified image
  2821. */
  2822. OpenLayers.Util.getImageLocation = function(image) {
  2823. return OpenLayers.Util.getImagesLocation() + image;
  2824. };
  2825. /**
  2826. * Function: Try
  2827. * Execute functions until one of them doesn't throw an error.
  2828. * Capitalized because "try" is a reserved word in JavaScript.
  2829. * Taken directly from OpenLayers.Util.Try()
  2830. *
  2831. * Parameters:
  2832. * [*] - {Function} Any number of parameters may be passed to Try()
  2833. * It will attempt to execute each of them until one of them
  2834. * successfully executes.
  2835. * If none executes successfully, returns null.
  2836. *
  2837. * Returns:
  2838. * {*} The value returned by the first successfully executed function.
  2839. */
  2840. OpenLayers.Util.Try = function() {
  2841. var returnValue = null;
  2842. for (var i=0, len=arguments.length; i<len; i++) {
  2843. var lambda = arguments[i];
  2844. try {
  2845. returnValue = lambda();
  2846. break;
  2847. } catch (e) {}
  2848. }
  2849. return returnValue;
  2850. };
  2851. /**
  2852. * Function: getXmlNodeValue
  2853. *
  2854. * Parameters:
  2855. * node - {XMLNode}
  2856. *
  2857. * Returns:
  2858. * {String} The text value of the given node, without breaking in firefox or IE
  2859. */
  2860. OpenLayers.Util.getXmlNodeValue = function(node) {
  2861. var val = null;
  2862. OpenLayers.Util.Try(
  2863. function() {
  2864. val = node.text;
  2865. if (!val) {
  2866. val = node.textContent;
  2867. }
  2868. if (!val) {
  2869. val = node.firstChild.nodeValue;
  2870. }
  2871. },
  2872. function() {
  2873. val = node.textContent;
  2874. });
  2875. return val;
  2876. };
  2877. /**
  2878. * Function: mouseLeft
  2879. *
  2880. * Parameters:
  2881. * evt - {Event}
  2882. * div - {HTMLDivElement}
  2883. *
  2884. * Returns:
  2885. * {Boolean}
  2886. */
  2887. OpenLayers.Util.mouseLeft = function (evt, div) {
  2888. // start with the element to which the mouse has moved
  2889. var target = (evt.relatedTarget) ? evt.relatedTarget : evt.toElement;
  2890. // walk up the DOM tree.
  2891. while (target != div && target != null) {
  2892. target = target.parentNode;
  2893. }
  2894. // if the target we stop at isn't the div, then we've left the div.
  2895. return (target != div);
  2896. };
  2897. /**
  2898. * Property: precision
  2899. * {Number} The number of significant digits to retain to avoid
  2900. * floating point precision errors.
  2901. *
  2902. * We use 14 as a "safe" default because, although IEEE 754 double floats
  2903. * (standard on most modern operating systems) support up to about 16
  2904. * significant digits, 14 significant digits are sufficient to represent
  2905. * sub-millimeter accuracy in any coordinate system that anyone is likely to
  2906. * use with OpenLayers.
  2907. *
  2908. * If DEFAULT_PRECISION is set to 0, the original non-truncating behavior
  2909. * of OpenLayers <2.8 is preserved. Be aware that this will cause problems
  2910. * with certain projections, e.g. spherical Mercator.
  2911. *
  2912. */
  2913. OpenLayers.Util.DEFAULT_PRECISION = 14;
  2914. /**
  2915. * Function: toFloat
  2916. * Convenience method to cast an object to a Number, rounded to the
  2917. * desired floating point precision.
  2918. *
  2919. * Parameters:
  2920. * number - {Number} The number to cast and round.
  2921. * precision - {Number} An integer suitable for use with
  2922. * Number.toPrecision(). Defaults to OpenLayers.Util.DEFAULT_PRECISION.
  2923. * If set to 0, no rounding is performed.
  2924. *
  2925. * Returns:
  2926. * {Number} The cast, rounded number.
  2927. */
  2928. OpenLayers.Util.toFloat = function (number, precision) {
  2929. if (precision == null) {
  2930. precision = OpenLayers.Util.DEFAULT_PRECISION;
  2931. }
  2932. if (typeof number !== "number") {
  2933. number = parseFloat(number);
  2934. }
  2935. return precision === 0 ? number :
  2936. parseFloat(number.toPrecision(precision));
  2937. };
  2938. /**
  2939. * Function: rad
  2940. *
  2941. * Parameters:
  2942. * x - {Float}
  2943. *
  2944. * Returns:
  2945. * {Float}
  2946. */
  2947. OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
  2948. /**
  2949. * Function: deg
  2950. *
  2951. * Parameters:
  2952. * x - {Float}
  2953. *
  2954. * Returns:
  2955. * {Float}
  2956. */
  2957. OpenLayers.Util.deg = function(x) {return x*180/Math.PI;};
  2958. /**
  2959. * Property: VincentyConstants
  2960. * {Object} Constants for Vincenty functions.
  2961. */
  2962. OpenLayers.Util.VincentyConstants = {
  2963. a: 6378137,
  2964. b: 6356752.3142,
  2965. f: 1/298.257223563
  2966. };
  2967. /**
  2968. * APIFunction: distVincenty
  2969. * Given two objects representing points with geographic coordinates, this
  2970. * calculates the distance between those points on the surface of an
  2971. * ellipsoid.
  2972. *
  2973. * Parameters:
  2974. * p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
  2975. * p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
  2976. *
  2977. * Returns:
  2978. * {Float} The distance (in km) between the two input points as measured on an
  2979. * ellipsoid. Note that the input point objects must be in geographic
  2980. * coordinates (decimal degrees) and the return distance is in kilometers.
  2981. */
  2982. OpenLayers.Util.distVincenty = function(p1, p2) {
  2983. var ct = OpenLayers.Util.VincentyConstants;
  2984. var a = ct.a, b = ct.b, f = ct.f;
  2985. var L = OpenLayers.Util.rad(p2.lon - p1.lon);
  2986. var U1 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p1.lat)));
  2987. var U2 = Math.atan((1-f) * Math.tan(OpenLayers.Util.rad(p2.lat)));
  2988. var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
  2989. var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
  2990. var lambda = L, lambdaP = 2*Math.PI;
  2991. var iterLimit = 20;
  2992. while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0) {
  2993. var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
  2994. var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
  2995. (cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
  2996. if (sinSigma==0) {
  2997. return 0; // co-incident points
  2998. }
  2999. var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
  3000. var sigma = Math.atan2(sinSigma, cosSigma);
  3001. var alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
  3002. var cosSqAlpha = Math.cos(alpha) * Math.cos(alpha);
  3003. var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
  3004. var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
  3005. lambdaP = lambda;
  3006. lambda = L + (1-C) * f * Math.sin(alpha) *
  3007. (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
  3008. }
  3009. if (iterLimit==0) {
  3010. return NaN; // formula failed to converge
  3011. }
  3012. var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
  3013. var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
  3014. var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
  3015. var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
  3016. B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
  3017. var s = b*A*(sigma-deltaSigma);
  3018. var d = s.toFixed(3)/1000; // round to 1mm precision
  3019. return d;
  3020. };
  3021. /**
  3022. * APIFunction: destinationVincenty
  3023. * Calculate destination point given start point lat/long (numeric degrees),
  3024. * bearing (numeric degrees) & distance (in m).
  3025. * Adapted from Chris Veness work, see
  3026. * http://www.movable-type.co.uk/scripts/latlong-vincenty-direct.html
  3027. *
  3028. * Parameters:
  3029. * lonlat - {<OpenLayers.LonLat>} (or any object with both .lat, .lon
  3030. * properties) The start point.
  3031. * brng - {Float} The bearing (degrees).
  3032. * dist - {Float} The ground distance (meters).
  3033. *
  3034. * Returns:
  3035. * {<OpenLayers.LonLat>} The destination point.
  3036. */
  3037. OpenLayers.Util.destinationVincenty = function(lonlat, brng, dist) {
  3038. var u = OpenLayers.Util;
  3039. var ct = u.VincentyConstants;
  3040. var a = ct.a, b = ct.b, f = ct.f;
  3041. var lon1 = lonlat.lon;
  3042. var lat1 = lonlat.lat;
  3043. var s = dist;
  3044. var alpha1 = u.rad(brng);
  3045. var sinAlpha1 = Math.sin(alpha1);
  3046. var cosAlpha1 = Math.cos(alpha1);
  3047. var tanU1 = (1-f) * Math.tan(u.rad(lat1));
  3048. var cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1*cosU1;
  3049. var sigma1 = Math.atan2(tanU1, cosAlpha1);
  3050. var sinAlpha = cosU1 * sinAlpha1;
  3051. var cosSqAlpha = 1 - sinAlpha*sinAlpha;
  3052. var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
  3053. var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
  3054. var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
  3055. var sigma = s / (b*A), sigmaP = 2*Math.PI;
  3056. while (Math.abs(sigma-sigmaP) > 1e-12) {
  3057. var cos2SigmaM = Math.cos(2*sigma1 + sigma);
  3058. var sinSigma = Math.sin(sigma);
  3059. var cosSigma = Math.cos(sigma);
  3060. var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
  3061. B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
  3062. sigmaP = sigma;
  3063. sigma = s / (b*A) + deltaSigma;
  3064. }
  3065. var tmp = sinU1*sinSigma - cosU1*cosSigma*cosAlpha1;
  3066. var lat2 = Math.atan2(sinU1*cosSigma + cosU1*sinSigma*cosAlpha1,
  3067. (1-f)*Math.sqrt(sinAlpha*sinAlpha + tmp*tmp));
  3068. var lambda = Math.atan2(sinSigma*sinAlpha1, cosU1*cosSigma - sinU1*sinSigma*cosAlpha1);
  3069. var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
  3070. var L = lambda - (1-C) * f * sinAlpha *
  3071. (sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
  3072. var revAz = Math.atan2(sinAlpha, -tmp); // final bearing
  3073. return new OpenLayers.LonLat(lon1+u.deg(L), u.deg(lat2));
  3074. };
  3075. /**
  3076. * Function: getParameters
  3077. * Parse the parameters from a URL or from the current page itself into a
  3078. * JavaScript Object. Note that parameter values with commas are separated
  3079. * out into an Array.
  3080. *
  3081. * Parameters:
  3082. * url - {String} Optional url used to extract the query string.
  3083. * If url is null or is not supplied, query string is taken
  3084. * from the page location.
  3085. *
  3086. * Returns:
  3087. * {Object} An object of key/value pairs from the query string.
  3088. */
  3089. OpenLayers.Util.getParameters = function(url) {
  3090. // if no url specified, take it from the location bar
  3091. url = (url === null || url === undefined) ? window.location.href : url;
  3092. //parse out parameters portion of url string
  3093. var paramsString = "";
  3094. if (OpenLayers.String.contains(url, '?')) {
  3095. var start = url.indexOf('?') + 1;
  3096. var end = OpenLayers.String.contains(url, "#") ?
  3097. url.indexOf('#') : url.length;
  3098. paramsString = url.substring(start, end);
  3099. }
  3100. var parameters = {};
  3101. var pairs = paramsString.split(/[&;]/);
  3102. for(var i=0, len=pairs.length; i<len; ++i) {
  3103. var keyValue = pairs[i].split('=');
  3104. if (keyValue[0]) {
  3105. var key = keyValue[0];
  3106. try {
  3107. key = decodeURIComponent(key);
  3108. } catch (err) {
  3109. key = unescape(key);
  3110. }
  3111. // being liberal by replacing "+" with " "
  3112. var value = (keyValue[1] || '').replace(/\+/g, " ");
  3113. try {
  3114. value = decodeURIComponent(value);
  3115. } catch (err) {
  3116. value = unescape(value);
  3117. }
  3118. // follow OGC convention of comma delimited values
  3119. value = value.split(",");
  3120. //if there's only one value, do not return as array
  3121. if (value.length == 1) {
  3122. value = value[0];
  3123. }
  3124. parameters[key] = value;
  3125. }
  3126. }
  3127. return parameters;
  3128. };
  3129. /**
  3130. * Property: lastSeqID
  3131. * {Integer} The ever-incrementing count variable.
  3132. * Used for generating unique ids.
  3133. */
  3134. OpenLayers.Util.lastSeqID = 0;
  3135. /**
  3136. * Function: createUniqueID
  3137. * Create a unique identifier for this session. Each time this function
  3138. * is called, a counter is incremented. The return will be the optional
  3139. * prefix (defaults to "id_") appended with the counter value.
  3140. *
  3141. * Parameters:
  3142. * prefix - {String} Optional string to prefix unique id. Default is "id_".
  3143. *
  3144. * Returns:
  3145. * {String} A unique id string, built on the passed in prefix.
  3146. */
  3147. OpenLayers.Util.createUniqueID = function(prefix) {
  3148. if (prefix == null) {
  3149. prefix = "id_";
  3150. }
  3151. OpenLayers.Util.lastSeqID += 1;
  3152. return prefix + OpenLayers.Util.lastSeqID;
  3153. };
  3154. /**
  3155. * Constant: INCHES_PER_UNIT
  3156. * {Object} Constant inches per unit -- borrowed from MapServer mapscale.c
  3157. * derivation of nautical miles from http://en.wikipedia.org/wiki/Nautical_mile
  3158. * Includes the full set of units supported by CS-MAP (http://trac.osgeo.org/csmap/)
  3159. * and PROJ.4 (http://trac.osgeo.org/proj/)
  3160. * The hardcoded table is maintain in a CS-MAP source code module named CSdataU.c
  3161. * The hardcoded table of PROJ.4 units are in pj_units.c.
  3162. */
  3163. OpenLayers.INCHES_PER_UNIT = {
  3164. 'inches': 1.0,
  3165. 'ft': 12.0,
  3166. 'mi': 63360.0,
  3167. 'm': 39.3701,
  3168. 'km': 39370.1,
  3169. 'dd': 4374754,
  3170. 'yd': 36
  3171. };
  3172. OpenLayers.INCHES_PER_UNIT["in"]= OpenLayers.INCHES_PER_UNIT.inches;
  3173. OpenLayers.INCHES_PER_UNIT["degrees"] = OpenLayers.INCHES_PER_UNIT.dd;
  3174. OpenLayers.INCHES_PER_UNIT["nmi"] = 1852 * OpenLayers.INCHES_PER_UNIT.m;
  3175. // Units from CS-Map
  3176. OpenLayers.METERS_PER_INCH = 0.02540005080010160020;
  3177. OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
  3178. "Inch": OpenLayers.INCHES_PER_UNIT.inches,
  3179. "Meter": 1.0 / OpenLayers.METERS_PER_INCH, //EPSG:9001
  3180. "Foot": 0.30480060960121920243 / OpenLayers.METERS_PER_INCH, //EPSG:9003
  3181. "IFoot": 0.30480000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9002
  3182. "ClarkeFoot": 0.3047972651151 / OpenLayers.METERS_PER_INCH, //EPSG:9005
  3183. "SearsFoot": 0.30479947153867624624 / OpenLayers.METERS_PER_INCH, //EPSG:9041
  3184. "GoldCoastFoot": 0.30479971018150881758 / OpenLayers.METERS_PER_INCH, //EPSG:9094
  3185. "IInch": 0.02540000000000000000 / OpenLayers.METERS_PER_INCH,
  3186. "MicroInch": 0.00002540000000000000 / OpenLayers.METERS_PER_INCH,
  3187. "Mil": 0.00000002540000000000 / OpenLayers.METERS_PER_INCH,
  3188. "Centimeter": 0.01000000000000000000 / OpenLayers.METERS_PER_INCH,
  3189. "Kilometer": 1000.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9036
  3190. "Yard": 0.91440182880365760731 / OpenLayers.METERS_PER_INCH,
  3191. "SearsYard": 0.914398414616029 / OpenLayers.METERS_PER_INCH, //EPSG:9040
  3192. "IndianYard": 0.91439853074444079983 / OpenLayers.METERS_PER_INCH, //EPSG:9084
  3193. "IndianYd37": 0.91439523 / OpenLayers.METERS_PER_INCH, //EPSG:9085
  3194. "IndianYd62": 0.9143988 / OpenLayers.METERS_PER_INCH, //EPSG:9086
  3195. "IndianYd75": 0.9143985 / OpenLayers.METERS_PER_INCH, //EPSG:9087
  3196. "IndianFoot": 0.30479951 / OpenLayers.METERS_PER_INCH, //EPSG:9080
  3197. "IndianFt37": 0.30479841 / OpenLayers.METERS_PER_INCH, //EPSG:9081
  3198. "IndianFt62": 0.3047996 / OpenLayers.METERS_PER_INCH, //EPSG:9082
  3199. "IndianFt75": 0.3047995 / OpenLayers.METERS_PER_INCH, //EPSG:9083
  3200. "Mile": 1609.34721869443738887477 / OpenLayers.METERS_PER_INCH,
  3201. "IYard": 0.91440000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9096
  3202. "IMile": 1609.34400000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9093
  3203. "NautM": 1852.00000000000000000000 / OpenLayers.METERS_PER_INCH, //EPSG:9030
  3204. "Lat-66": 110943.316488932731 / OpenLayers.METERS_PER_INCH,
  3205. "Lat-83": 110946.25736872234125 / OpenLayers.METERS_PER_INCH,
  3206. "Decimeter": 0.10000000000000000000 / OpenLayers.METERS_PER_INCH,
  3207. "Millimeter": 0.00100000000000000000 / OpenLayers.METERS_PER_INCH,
  3208. "Dekameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
  3209. "Decameter": 10.00000000000000000000 / OpenLayers.METERS_PER_INCH,
  3210. "Hectometer": 100.00000000000000000000 / OpenLayers.METERS_PER_INCH,
  3211. "GermanMeter": 1.0000135965 / OpenLayers.METERS_PER_INCH, //EPSG:9031
  3212. "CaGrid": 0.999738 / OpenLayers.METERS_PER_INCH,
  3213. "ClarkeChain": 20.1166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9038
  3214. "GunterChain": 20.11684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9033
  3215. "BenoitChain": 20.116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9062
  3216. "SearsChain": 20.11676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9042
  3217. "ClarkeLink": 0.201166194976 / OpenLayers.METERS_PER_INCH, //EPSG:9039
  3218. "GunterLink": 0.2011684023368047 / OpenLayers.METERS_PER_INCH, //EPSG:9034
  3219. "BenoitLink": 0.20116782494375872 / OpenLayers.METERS_PER_INCH, //EPSG:9063
  3220. "SearsLink": 0.2011676512155 / OpenLayers.METERS_PER_INCH, //EPSG:9043
  3221. "Rod": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
  3222. "IntnlChain": 20.1168 / OpenLayers.METERS_PER_INCH, //EPSG:9097
  3223. "IntnlLink": 0.201168 / OpenLayers.METERS_PER_INCH, //EPSG:9098
  3224. "Perch": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
  3225. "Pole": 5.02921005842012 / OpenLayers.METERS_PER_INCH,
  3226. "Furlong": 201.1684023368046 / OpenLayers.METERS_PER_INCH,
  3227. "Rood": 3.778266898 / OpenLayers.METERS_PER_INCH,
  3228. "CapeFoot": 0.3047972615 / OpenLayers.METERS_PER_INCH,
  3229. "Brealey": 375.00000000000000000000 / OpenLayers.METERS_PER_INCH,
  3230. "ModAmFt": 0.304812252984505969011938 / OpenLayers.METERS_PER_INCH,
  3231. "Fathom": 1.8288 / OpenLayers.METERS_PER_INCH,
  3232. "NautM-UK": 1853.184 / OpenLayers.METERS_PER_INCH,
  3233. "50kilometers": 50000.0 / OpenLayers.METERS_PER_INCH,
  3234. "150kilometers": 150000.0 / OpenLayers.METERS_PER_INCH
  3235. });
  3236. //unit abbreviations supported by PROJ.4
  3237. OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT, {
  3238. "mm": OpenLayers.INCHES_PER_UNIT["Meter"] / 1000.0,
  3239. "cm": OpenLayers.INCHES_PER_UNIT["Meter"] / 100.0,
  3240. "dm": OpenLayers.INCHES_PER_UNIT["Meter"] * 100.0,
  3241. "km": OpenLayers.INCHES_PER_UNIT["Meter"] * 1000.0,
  3242. "kmi": OpenLayers.INCHES_PER_UNIT["nmi"], //International Nautical Mile
  3243. "fath": OpenLayers.INCHES_PER_UNIT["Fathom"], //International Fathom
  3244. "ch": OpenLayers.INCHES_PER_UNIT["IntnlChain"], //International Chain
  3245. "link": OpenLayers.INCHES_PER_UNIT["IntnlLink"], //International Link
  3246. "us-in": OpenLayers.INCHES_PER_UNIT["inches"], //U.S. Surveyor's Inch
  3247. "us-ft": OpenLayers.INCHES_PER_UNIT["Foot"], //U.S. Surveyor's Foot
  3248. "us-yd": OpenLayers.INCHES_PER_UNIT["Yard"], //U.S. Surveyor's Yard
  3249. "us-ch": OpenLayers.INCHES_PER_UNIT["GunterChain"], //U.S. Surveyor's Chain
  3250. "us-mi": OpenLayers.INCHES_PER_UNIT["Mile"], //U.S. Surveyor's Statute Mile
  3251. "ind-yd": OpenLayers.INCHES_PER_UNIT["IndianYd37"], //Indian Yard
  3252. "ind-ft": OpenLayers.INCHES_PER_UNIT["IndianFt37"], //Indian Foot
  3253. "ind-ch": 20.11669506 / OpenLayers.METERS_PER_INCH //Indian Chain
  3254. });
  3255. /**
  3256. * Constant: DOTS_PER_INCH
  3257. * {Integer} 72 (A sensible default)
  3258. */
  3259. OpenLayers.DOTS_PER_INCH = 72;
  3260. /**
  3261. * Function: normalizeScale
  3262. *
  3263. * Parameters:
  3264. * scale - {float}
  3265. *
  3266. * Returns:
  3267. * {Float} A normalized scale value, in 1 / X format.
  3268. * This means that if a value less than one ( already 1/x) is passed
  3269. * in, it just returns scale directly. Otherwise, it returns
  3270. * 1 / scale
  3271. */
  3272. OpenLayers.Util.normalizeScale = function (scale) {
  3273. var normScale = (scale > 1.0) ? (1.0 / scale)
  3274. : scale;
  3275. return normScale;
  3276. };
  3277. /**
  3278. * Function: getResolutionFromScale
  3279. *
  3280. * Parameters:
  3281. * scale - {Float}
  3282. * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
  3283. * Default is degrees
  3284. *
  3285. * Returns:
  3286. * {Float} The corresponding resolution given passed-in scale and unit
  3287. * parameters. If the given scale is falsey, the returned resolution will
  3288. * be undefined.
  3289. */
  3290. OpenLayers.Util.getResolutionFromScale = function (scale, units) {
  3291. var resolution;
  3292. if (scale) {
  3293. if (units == null) {
  3294. units = "degrees";
  3295. }
  3296. var normScale = OpenLayers.Util.normalizeScale(scale);
  3297. resolution = 1 / (normScale * OpenLayers.INCHES_PER_UNIT[units]
  3298. * OpenLayers.DOTS_PER_INCH);
  3299. }
  3300. return resolution;
  3301. };
  3302. /**
  3303. * Function: getScaleFromResolution
  3304. *
  3305. * Parameters:
  3306. * resolution - {Float}
  3307. * units - {String} Index into OpenLayers.INCHES_PER_UNIT hashtable.
  3308. * Default is degrees
  3309. *
  3310. * Returns:
  3311. * {Float} The corresponding scale given passed-in resolution and unit
  3312. * parameters.
  3313. */
  3314. OpenLayers.Util.getScaleFromResolution = function (resolution, units) {
  3315. if (units == null) {
  3316. units = "degrees";
  3317. }
  3318. var scale = resolution * OpenLayers.INCHES_PER_UNIT[units] *
  3319. OpenLayers.DOTS_PER_INCH;
  3320. return scale;
  3321. };
  3322. /**
  3323. * Function: pagePosition
  3324. * Calculates the position of an element on the page (see
  3325. * http://code.google.com/p/doctype/wiki/ArticlePageOffset)
  3326. *
  3327. * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
  3328. * Copyright (c) 2006, Yahoo! Inc.
  3329. * All rights reserved.
  3330. *
  3331. * Redistribution and use of this software in source and binary forms, with or
  3332. * without modification, are permitted provided that the following conditions
  3333. * are met:
  3334. *
  3335. * * Redistributions of source code must retain the above copyright notice,
  3336. * this list of conditions and the following disclaimer.
  3337. *
  3338. * * Redistributions in binary form must reproduce the above copyright notice,
  3339. * this list of conditions and the following disclaimer in the documentation
  3340. * and/or other materials provided with the distribution.
  3341. *
  3342. * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
  3343. * used to endorse or promote products derived from this software without
  3344. * specific prior written permission of Yahoo! Inc.
  3345. *
  3346. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  3347. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  3348. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  3349. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  3350. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  3351. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  3352. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  3353. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  3354. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  3355. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  3356. * POSSIBILITY OF SUCH DAMAGE.
  3357. *
  3358. * Parameters:
  3359. * forElement - {DOMElement}
  3360. *
  3361. * Returns:
  3362. * {Array} two item array, Left value then Top value.
  3363. */
  3364. OpenLayers.Util.pagePosition = function(forElement) {
  3365. // NOTE: If element is hidden (display none or disconnected or any the
  3366. // ancestors are hidden) we get (0,0) by default but we still do the
  3367. // accumulation of scroll position.
  3368. var pos = [0, 0];
  3369. var viewportElement = OpenLayers.Util.getViewportElement();
  3370. if (!forElement || forElement == window || forElement == viewportElement) {
  3371. // viewport is always at 0,0 as that defined the coordinate system for
  3372. // this function - this avoids special case checks in the code below
  3373. return pos;
  3374. }
  3375. // Gecko browsers normally use getBoxObjectFor to calculate the position.
  3376. // When invoked for an element with an implicit absolute position though it
  3377. // can be off by one. Therefore the recursive implementation is used in
  3378. // those (relatively rare) cases.
  3379. var BUGGY_GECKO_BOX_OBJECT =
  3380. OpenLayers.IS_GECKO && document.getBoxObjectFor &&
  3381. OpenLayers.Element.getStyle(forElement, 'position') == 'absolute' &&
  3382. (forElement.style.top == '' || forElement.style.left == '');
  3383. var parent = null;
  3384. var box;
  3385. if (forElement.getBoundingClientRect) { // IE
  3386. box = forElement.getBoundingClientRect();
  3387. var scrollTop = viewportElement.scrollTop;
  3388. var scrollLeft = viewportElement.scrollLeft;
  3389. pos[0] = box.left + scrollLeft;
  3390. pos[1] = box.top + scrollTop;
  3391. } else if (document.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT) { // gecko
  3392. // Gecko ignores the scroll values for ancestors, up to 1.9. See:
  3393. // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
  3394. // https://bugzilla.mozilla.org/show_bug.cgi?id=330619
  3395. box = document.getBoxObjectFor(forElement);
  3396. var vpBox = document.getBoxObjectFor(viewportElement);
  3397. pos[0] = box.screenX - vpBox.screenX;
  3398. pos[1] = box.screenY - vpBox.screenY;
  3399. } else { // safari/opera
  3400. pos[0] = forElement.offsetLeft;
  3401. pos[1] = forElement.offsetTop;
  3402. parent = forElement.offsetParent;
  3403. if (parent != forElement) {
  3404. while (parent) {
  3405. pos[0] += parent.offsetLeft;
  3406. pos[1] += parent.offsetTop;
  3407. parent = parent.offsetParent;
  3408. }
  3409. }
  3410. var browser = OpenLayers.BROWSER_NAME;
  3411. // opera & (safari absolute) incorrectly account for body offsetTop
  3412. if (browser == "opera" || (browser == "safari" &&
  3413. OpenLayers.Element.getStyle(forElement, 'position') == 'absolute')) {
  3414. pos[1] -= document.body.offsetTop;
  3415. }
  3416. // accumulate the scroll positions for everything but the body element
  3417. parent = forElement.offsetParent;
  3418. while (parent && parent != document.body) {
  3419. pos[0] -= parent.scrollLeft;
  3420. // see https://bugs.opera.com/show_bug.cgi?id=249965
  3421. if (browser != "opera" || parent.tagName != 'TR') {
  3422. pos[1] -= parent.scrollTop;
  3423. }
  3424. parent = parent.offsetParent;
  3425. }
  3426. }
  3427. return pos;
  3428. };
  3429. /**
  3430. * Function: getViewportElement
  3431. * Returns die viewport element of the document. The viewport element is
  3432. * usually document.documentElement, except in IE,where it is either
  3433. * document.body or document.documentElement, depending on the document's
  3434. * compatibility mode (see
  3435. * http://code.google.com/p/doctype/wiki/ArticleClientViewportElement)
  3436. *
  3437. * Returns:
  3438. * {DOMElement}
  3439. */
  3440. OpenLayers.Util.getViewportElement = function() {
  3441. var viewportElement = arguments.callee.viewportElement;
  3442. if (viewportElement == undefined) {
  3443. viewportElement = (OpenLayers.BROWSER_NAME == "msie" &&
  3444. document.compatMode != 'CSS1Compat') ? document.body :
  3445. document.documentElement;
  3446. arguments.callee.viewportElement = viewportElement;
  3447. }
  3448. return viewportElement;
  3449. };
  3450. /**
  3451. * Function: isEquivalentUrl
  3452. * Test two URLs for equivalence.
  3453. *
  3454. * Setting 'ignoreCase' allows for case-independent comparison.
  3455. *
  3456. * Comparison is based on:
  3457. * - Protocol
  3458. * - Host (evaluated without the port)
  3459. * - Port (set 'ignorePort80' to ignore "80" values)
  3460. * - Hash ( set 'ignoreHash' to disable)
  3461. * - Pathname (for relative <-> absolute comparison)
  3462. * - Arguments (so they can be out of order)
  3463. *
  3464. * Parameters:
  3465. * url1 - {String}
  3466. * url2 - {String}
  3467. * options - {Object} Allows for customization of comparison:
  3468. * 'ignoreCase' - Default is True
  3469. * 'ignorePort80' - Default is True
  3470. * 'ignoreHash' - Default is True
  3471. *
  3472. * Returns:
  3473. * {Boolean} Whether or not the two URLs are equivalent
  3474. */
  3475. OpenLayers.Util.isEquivalentUrl = function(url1, url2, options) {
  3476. options = options || {};
  3477. OpenLayers.Util.applyDefaults(options, {
  3478. ignoreCase: true,
  3479. ignorePort80: true,
  3480. ignoreHash: true
  3481. });
  3482. var urlObj1 = OpenLayers.Util.createUrlObject(url1, options);
  3483. var urlObj2 = OpenLayers.Util.createUrlObject(url2, options);
  3484. //compare all keys except for "args" (treated below)
  3485. for(var key in urlObj1) {
  3486. if(key !== "args") {
  3487. if(urlObj1[key] != urlObj2[key]) {
  3488. return false;
  3489. }
  3490. }
  3491. }
  3492. // compare search args - irrespective of order
  3493. for(var key in urlObj1.args) {
  3494. if(urlObj1.args[key] != urlObj2.args[key]) {
  3495. return false;
  3496. }
  3497. delete urlObj2.args[key];
  3498. }
  3499. // urlObj2 shouldn't have any args left
  3500. for(var key in urlObj2.args) {
  3501. return false;
  3502. }
  3503. return true;
  3504. };
  3505. /**
  3506. * Function: createUrlObject
  3507. *
  3508. * Parameters:
  3509. * url - {String}
  3510. * options - {Object} A hash of options.
  3511. *
  3512. * Valid options:
  3513. * ignoreCase - {Boolean} lowercase url,
  3514. * ignorePort80 - {Boolean} don't include explicit port if port is 80,
  3515. * ignoreHash - {Boolean} Don't include part of url after the hash (#).
  3516. *
  3517. * Returns:
  3518. * {Object} An object with separate url, a, port, host, and args parsed out
  3519. * and ready for comparison
  3520. */
  3521. OpenLayers.Util.createUrlObject = function(url, options) {
  3522. options = options || {};
  3523. // deal with relative urls first
  3524. if(!(/^\w+:\/\//).test(url)) {
  3525. var loc = window.location;
  3526. var port = loc.port ? ":" + loc.port : "";
  3527. var fullUrl = loc.protocol + "//" + loc.host.split(":").shift() + port;
  3528. if(url.indexOf("/") === 0) {
  3529. // full pathname
  3530. url = fullUrl + url;
  3531. } else {
  3532. // relative to current path
  3533. var parts = loc.pathname.split("/");
  3534. parts.pop();
  3535. url = fullUrl + parts.join("/") + "/" + url;
  3536. }
  3537. }
  3538. if (options.ignoreCase) {
  3539. url = url.toLowerCase();
  3540. }
  3541. var a = document.createElement('a');
  3542. a.href = url;
  3543. var urlObject = {};
  3544. //host (without port)
  3545. urlObject.host = a.host.split(":").shift();
  3546. //protocol
  3547. urlObject.protocol = a.protocol;
  3548. //port (get uniform browser behavior with port 80 here)
  3549. if(options.ignorePort80) {
  3550. urlObject.port = (a.port == "80" || a.port == "0") ? "" : a.port;
  3551. } else {
  3552. urlObject.port = (a.port == "" || a.port == "0") ? "80" : a.port;
  3553. }
  3554. //hash
  3555. urlObject.hash = (options.ignoreHash || a.hash === "#") ? "" : a.hash;
  3556. //args
  3557. var queryString = a.search;
  3558. if (!queryString) {
  3559. var qMark = url.indexOf("?");
  3560. queryString = (qMark != -1) ? url.substr(qMark) : "";
  3561. }
  3562. urlObject.args = OpenLayers.Util.getParameters(queryString);
  3563. // pathname
  3564. //
  3565. // This is a workaround for Internet Explorer where
  3566. // window.location.pathname has a leading "/", but
  3567. // a.pathname has no leading "/".
  3568. urlObject.pathname = (a.pathname.charAt(0) == "/") ? a.pathname : "/" + a.pathname;
  3569. return urlObject;
  3570. };
  3571. /**
  3572. * Function: removeTail
  3573. * Takes a url and removes everything after the ? and #
  3574. *
  3575. * Parameters:
  3576. * url - {String} The url to process
  3577. *
  3578. * Returns:
  3579. * {String} The string with all queryString and Hash removed
  3580. */
  3581. OpenLayers.Util.removeTail = function(url) {
  3582. var head = null;
  3583. var qMark = url.indexOf("?");
  3584. var hashMark = url.indexOf("#");
  3585. if (qMark == -1) {
  3586. head = (hashMark != -1) ? url.substr(0,hashMark) : url;
  3587. } else {
  3588. head = (hashMark != -1) ? url.substr(0,Math.min(qMark, hashMark))
  3589. : url.substr(0, qMark);
  3590. }
  3591. return head;
  3592. };
  3593. /**
  3594. * Constant: IS_GECKO
  3595. * {Boolean} True if the userAgent reports the browser to use the Gecko engine
  3596. */
  3597. OpenLayers.IS_GECKO = (function() {
  3598. var ua = navigator.userAgent.toLowerCase();
  3599. return ua.indexOf("webkit") == -1 && ua.indexOf("gecko") != -1;
  3600. })();
  3601. /**
  3602. * Constant: CANVAS_SUPPORTED
  3603. * {Boolean} True if canvas 2d is supported.
  3604. */
  3605. OpenLayers.CANVAS_SUPPORTED = (function() {
  3606. var elem = document.createElement('canvas');
  3607. return !!(elem.getContext && elem.getContext('2d'));
  3608. })();
  3609. /**
  3610. * Constant: BROWSER_NAME
  3611. * {String}
  3612. * A substring of the navigator.userAgent property. Depending on the userAgent
  3613. * property, this will be the empty string or one of the following:
  3614. * * "opera" -- Opera
  3615. * * "msie" -- Internet Explorer
  3616. * * "safari" -- Safari
  3617. * * "firefox" -- Firefox
  3618. * * "mozilla" -- Mozilla
  3619. */
  3620. OpenLayers.BROWSER_NAME = (function() {
  3621. var name = "";
  3622. var ua = navigator.userAgent.toLowerCase();
  3623. if (ua.indexOf("opera") != -1) {
  3624. name = "opera";
  3625. } else if (ua.indexOf("msie") != -1) {
  3626. name = "msie";
  3627. } else if (ua.indexOf("safari") != -1) {
  3628. name = "safari";
  3629. } else if (ua.indexOf("mozilla") != -1) {
  3630. if (ua.indexOf("firefox") != -1) {
  3631. name = "firefox";
  3632. } else {
  3633. name = "mozilla";
  3634. }
  3635. }
  3636. return name;
  3637. })();
  3638. /**
  3639. * Function: getBrowserName
  3640. *
  3641. * Returns:
  3642. * {String} A string which specifies which is the current
  3643. * browser in which we are running.
  3644. *
  3645. * Currently-supported browser detection and codes:
  3646. * * 'opera' -- Opera
  3647. * * 'msie' -- Internet Explorer
  3648. * * 'safari' -- Safari
  3649. * * 'firefox' -- Firefox
  3650. * * 'mozilla' -- Mozilla
  3651. *
  3652. * If we are unable to property identify the browser, we
  3653. * return an empty string.
  3654. */
  3655. OpenLayers.Util.getBrowserName = function() {
  3656. return OpenLayers.BROWSER_NAME;
  3657. };
  3658. /**
  3659. * Method: getRenderedDimensions
  3660. * Renders the contentHTML offscreen to determine actual dimensions for
  3661. * popup sizing. As we need layout to determine dimensions the content
  3662. * is rendered -9999px to the left and absolute to ensure the
  3663. * scrollbars do not flicker
  3664. *
  3665. * Parameters:
  3666. * contentHTML
  3667. * size - {<OpenLayers.Size>} If either the 'w' or 'h' properties is
  3668. * specified, we fix that dimension of the div to be measured. This is
  3669. * useful in the case where we have a limit in one dimension and must
  3670. * therefore meaure the flow in the other dimension.
  3671. * options - {Object}
  3672. *
  3673. * Allowed Options:
  3674. * displayClass - {String} Optional parameter. A CSS class name(s) string
  3675. * to provide the CSS context of the rendered content.
  3676. * containerElement - {DOMElement} Optional parameter. Insert the HTML to
  3677. * this node instead of the body root when calculating dimensions.
  3678. *
  3679. * Returns:
  3680. * {<OpenLayers.Size>}
  3681. */
  3682. OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
  3683. var w, h;
  3684. // create temp container div with restricted size
  3685. var container = document.createElement("div");
  3686. container.style.visibility = "hidden";
  3687. var containerElement = (options && options.containerElement)
  3688. ? options.containerElement : document.body;
  3689. // Opera and IE7 can't handle a node with position:aboslute if it inherits
  3690. // position:absolute from a parent.
  3691. var parentHasPositionAbsolute = false;
  3692. var superContainer = null;
  3693. var parent = containerElement;
  3694. while (parent && parent.tagName.toLowerCase()!="body") {
  3695. var parentPosition = OpenLayers.Element.getStyle(parent, "position");
  3696. if(parentPosition == "absolute") {
  3697. parentHasPositionAbsolute = true;
  3698. break;
  3699. } else if (parentPosition && parentPosition != "static") {
  3700. break;
  3701. }
  3702. parent = parent.parentNode;
  3703. }
  3704. if(parentHasPositionAbsolute && (containerElement.clientHeight === 0 ||
  3705. containerElement.clientWidth === 0) ){
  3706. superContainer = document.createElement("div");
  3707. superContainer.style.visibility = "hidden";
  3708. superContainer.style.position = "absolute";
  3709. superContainer.style.overflow = "visible";
  3710. superContainer.style.width = document.body.clientWidth + "px";
  3711. superContainer.style.height = document.body.clientHeight + "px";
  3712. superContainer.appendChild(container);
  3713. }
  3714. container.style.position = "absolute";
  3715. //fix a dimension, if specified.
  3716. if (size) {
  3717. if (size.w) {
  3718. w = size.w;
  3719. container.style.width = w + "px";
  3720. } else if (size.h) {
  3721. h = size.h;
  3722. container.style.height = h + "px";
  3723. }
  3724. }
  3725. //add css classes, if specified
  3726. if (options && options.displayClass) {
  3727. container.className = options.displayClass;
  3728. }
  3729. // create temp content div and assign content
  3730. var content = document.createElement("div");
  3731. content.innerHTML = contentHTML;
  3732. // we need overflow visible when calculating the size
  3733. content.style.overflow = "visible";
  3734. if (content.childNodes) {
  3735. for (var i=0, l=content.childNodes.length; i<l; i++) {
  3736. if (!content.childNodes[i].style) continue;
  3737. content.childNodes[i].style.overflow = "visible";
  3738. }
  3739. }
  3740. // add content to restricted container
  3741. container.appendChild(content);
  3742. // append container to body for rendering
  3743. if (superContainer) {
  3744. containerElement.appendChild(superContainer);
  3745. } else {
  3746. containerElement.appendChild(container);
  3747. }
  3748. // calculate scroll width of content and add corners and shadow width
  3749. if (!w) {
  3750. w = parseInt(content.scrollWidth);
  3751. // update container width to allow height to adjust
  3752. container.style.width = w + "px";
  3753. }
  3754. // capture height and add shadow and corner image widths
  3755. if (!h) {
  3756. h = parseInt(content.scrollHeight);
  3757. }
  3758. // remove elements
  3759. container.removeChild(content);
  3760. if (superContainer) {
  3761. superContainer.removeChild(container);
  3762. containerElement.removeChild(superContainer);
  3763. } else {
  3764. containerElement.removeChild(container);
  3765. }
  3766. return new OpenLayers.Size(w, h);
  3767. };
  3768. /**
  3769. * APIFunction: getScrollbarWidth
  3770. * This function has been modified by the OpenLayers from the original version,
  3771. * written by Matthew Eernisse and released under the Apache 2
  3772. * license here:
  3773. *
  3774. * http://www.fleegix.org/articles/2006/05/30/getting-the-scrollbar-width-in-pixels
  3775. *
  3776. * It has been modified simply to cache its value, since it is physically
  3777. * impossible that this code could ever run in more than one browser at
  3778. * once.
  3779. *
  3780. * Returns:
  3781. * {Integer}
  3782. */
  3783. OpenLayers.Util.getScrollbarWidth = function() {
  3784. var scrollbarWidth = OpenLayers.Util._scrollbarWidth;
  3785. if (scrollbarWidth == null) {
  3786. var scr = null;
  3787. var inn = null;
  3788. var wNoScroll = 0;
  3789. var wScroll = 0;
  3790. // Outer scrolling div
  3791. scr = document.createElement('div');
  3792. scr.style.position = 'absolute';
  3793. scr.style.top = '-1000px';
  3794. scr.style.left = '-1000px';
  3795. scr.style.width = '100px';
  3796. scr.style.height = '50px';
  3797. // Start with no scrollbar
  3798. scr.style.overflow = 'hidden';
  3799. // Inner content div
  3800. inn = document.createElement('div');
  3801. inn.style.width = '100%';
  3802. inn.style.height = '200px';
  3803. // Put the inner div in the scrolling div
  3804. scr.appendChild(inn);
  3805. // Append the scrolling div to the doc
  3806. document.body.appendChild(scr);
  3807. // Width of the inner div sans scrollbar
  3808. wNoScroll = inn.offsetWidth;
  3809. // Add the scrollbar
  3810. scr.style.overflow = 'scroll';
  3811. // Width of the inner div width scrollbar
  3812. wScroll = inn.offsetWidth;
  3813. // Remove the scrolling div from the doc
  3814. document.body.removeChild(document.body.lastChild);
  3815. // Pixel width of the scroller
  3816. OpenLayers.Util._scrollbarWidth = (wNoScroll - wScroll);
  3817. scrollbarWidth = OpenLayers.Util._scrollbarWidth;
  3818. }
  3819. return scrollbarWidth;
  3820. };
  3821. /**
  3822. * APIFunction: getFormattedLonLat
  3823. * This function will return latitude or longitude value formatted as
  3824. *
  3825. * Parameters:
  3826. * coordinate - {Float} the coordinate value to be formatted
  3827. * axis - {String} value of either 'lat' or 'lon' to indicate which axis is to
  3828. * to be formatted (default = lat)
  3829. * dmsOption - {String} specify the precision of the output can be one of:
  3830. * 'dms' show degrees minutes and seconds
  3831. * 'dm' show only degrees and minutes
  3832. * 'd' show only degrees
  3833. *
  3834. * Returns:
  3835. * {String} the coordinate value formatted as a string
  3836. */
  3837. OpenLayers.Util.getFormattedLonLat = function(coordinate, axis, dmsOption) {
  3838. if (!dmsOption) {
  3839. dmsOption = 'dms'; //default to show degree, minutes, seconds
  3840. }
  3841. coordinate = (coordinate+540)%360 - 180; // normalize for sphere being round
  3842. var abscoordinate = Math.abs(coordinate);
  3843. var coordinatedegrees = Math.floor(abscoordinate);
  3844. var coordinateminutes = (abscoordinate - coordinatedegrees)/(1/60);
  3845. var tempcoordinateminutes = coordinateminutes;
  3846. coordinateminutes = Math.floor(coordinateminutes);
  3847. var coordinateseconds = (tempcoordinateminutes - coordinateminutes)/(1/60);
  3848. coordinateseconds = Math.round(coordinateseconds*10);
  3849. coordinateseconds /= 10;
  3850. if( coordinateseconds >= 60) {
  3851. coordinateseconds -= 60;
  3852. coordinateminutes += 1;
  3853. if( coordinateminutes >= 60) {
  3854. coordinateminutes -= 60;
  3855. coordinatedegrees += 1;
  3856. }
  3857. }
  3858. if( coordinatedegrees < 10 ) {
  3859. coordinatedegrees = "0" + coordinatedegrees;
  3860. }
  3861. var str = coordinatedegrees + "\u00B0";
  3862. if (dmsOption.indexOf('dm') >= 0) {
  3863. if( coordinateminutes < 10 ) {
  3864. coordinateminutes = "0" + coordinateminutes;
  3865. }
  3866. str += coordinateminutes + "'";
  3867. if (dmsOption.indexOf('dms') >= 0) {
  3868. if( coordinateseconds < 10 ) {
  3869. coordinateseconds = "0" + coordinateseconds;
  3870. }
  3871. str += coordinateseconds + '"';
  3872. }
  3873. }
  3874. if (axis == "lon") {
  3875. str += coordinate < 0 ? OpenLayers.i18n("W") : OpenLayers.i18n("E");
  3876. } else {
  3877. str += coordinate < 0 ? OpenLayers.i18n("S") : OpenLayers.i18n("N");
  3878. }
  3879. return str;
  3880. };
  3881. /* ======================================================================
  3882. OpenLayers/Format.js
  3883. ====================================================================== */
  3884. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  3885. * full list of contributors). Published under the 2-clause BSD license.
  3886. * See license.txt in the OpenLayers distribution or repository for the
  3887. * full text of the license. */
  3888. /**
  3889. * @requires OpenLayers/BaseTypes/Class.js
  3890. * @requires OpenLayers/Util.js
  3891. */
  3892. /**
  3893. * Class: OpenLayers.Format
  3894. * Base class for format reading/writing a variety of formats. Subclasses
  3895. * of OpenLayers.Format are expected to have read and write methods.
  3896. */
  3897. OpenLayers.Format = OpenLayers.Class({
  3898. /**
  3899. * Property: options
  3900. * {Object} A reference to options passed to the constructor.
  3901. */
  3902. options: null,
  3903. /**
  3904. * APIProperty: externalProjection
  3905. * {<OpenLayers.Projection>} When passed a externalProjection and
  3906. * internalProjection, the format will reproject the geometries it
  3907. * reads or writes. The externalProjection is the projection used by
  3908. * the content which is passed into read or which comes out of write.
  3909. * In order to reproject, a projection transformation function for the
  3910. * specified projections must be available. This support may be
  3911. * provided via proj4js or via a custom transformation function. See
  3912. * {<OpenLayers.Projection.addTransform>} for more information on
  3913. * custom transformations.
  3914. */
  3915. externalProjection: null,
  3916. /**
  3917. * APIProperty: internalProjection
  3918. * {<OpenLayers.Projection>} When passed a externalProjection and
  3919. * internalProjection, the format will reproject the geometries it
  3920. * reads or writes. The internalProjection is the projection used by
  3921. * the geometries which are returned by read or which are passed into
  3922. * write. In order to reproject, a projection transformation function
  3923. * for the specified projections must be available. This support may be
  3924. * provided via proj4js or via a custom transformation function. See
  3925. * {<OpenLayers.Projection.addTransform>} for more information on
  3926. * custom transformations.
  3927. */
  3928. internalProjection: null,
  3929. /**
  3930. * APIProperty: data
  3931. * {Object} When <keepData> is true, this is the parsed string sent to
  3932. * <read>.
  3933. */
  3934. data: null,
  3935. /**
  3936. * APIProperty: keepData
  3937. * {Object} Maintain a reference (<data>) to the most recently read data.
  3938. * Default is false.
  3939. */
  3940. keepData: false,
  3941. /**
  3942. * Constructor: OpenLayers.Format
  3943. * Instances of this class are not useful. See one of the subclasses.
  3944. *
  3945. * Parameters:
  3946. * options - {Object} An optional object with properties to set on the
  3947. * format
  3948. *
  3949. * Valid options:
  3950. * keepData - {Boolean} If true, upon <read>, the data property will be
  3951. * set to the parsed object (e.g. the json or xml object).
  3952. *
  3953. * Returns:
  3954. * An instance of OpenLayers.Format
  3955. */
  3956. initialize: function(options) {
  3957. OpenLayers.Util.extend(this, options);
  3958. this.options = options;
  3959. },
  3960. /**
  3961. * APIMethod: destroy
  3962. * Clean up.
  3963. */
  3964. destroy: function() {
  3965. },
  3966. /**
  3967. * Method: read
  3968. * Read data from a string, and return an object whose type depends on the
  3969. * subclass.
  3970. *
  3971. * Parameters:
  3972. * data - {string} Data to read/parse.
  3973. *
  3974. * Returns:
  3975. * Depends on the subclass
  3976. */
  3977. read: function(data) {
  3978. throw new Error('Read not implemented.');
  3979. },
  3980. /**
  3981. * Method: write
  3982. * Accept an object, and return a string.
  3983. *
  3984. * Parameters:
  3985. * object - {Object} Object to be serialized
  3986. *
  3987. * Returns:
  3988. * {String} A string representation of the object.
  3989. */
  3990. write: function(object) {
  3991. throw new Error('Write not implemented.');
  3992. },
  3993. CLASS_NAME: "OpenLayers.Format"
  3994. });
  3995. /* ======================================================================
  3996. OpenLayers/Format/CSWGetRecords.js
  3997. ====================================================================== */
  3998. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  3999. * full list of contributors). Published under the 2-clause BSD license.
  4000. * See license.txt in the OpenLayers distribution or repository for the
  4001. * full text of the license. */
  4002. /**
  4003. * @requires OpenLayers/Format.js
  4004. */
  4005. /**
  4006. * Class: OpenLayers.Format.CSWGetRecords
  4007. * Default version is 2.0.2.
  4008. *
  4009. * Returns:
  4010. * {<OpenLayers.Format>} A CSWGetRecords format of the given version.
  4011. */
  4012. OpenLayers.Format.CSWGetRecords = function(options) {
  4013. options = OpenLayers.Util.applyDefaults(
  4014. options, OpenLayers.Format.CSWGetRecords.DEFAULTS
  4015. );
  4016. var cls = OpenLayers.Format.CSWGetRecords["v"+options.version.replace(/\./g, "_")];
  4017. if(!cls) {
  4018. throw "Unsupported CSWGetRecords version: " + options.version;
  4019. }
  4020. return new cls(options);
  4021. };
  4022. /**
  4023. * Constant: DEFAULTS
  4024. * {Object} Default properties for the CSWGetRecords format.
  4025. */
  4026. OpenLayers.Format.CSWGetRecords.DEFAULTS = {
  4027. "version": "2.0.2"
  4028. };
  4029. /* ======================================================================
  4030. OpenLayers/Control.js
  4031. ====================================================================== */
  4032. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  4033. * full list of contributors). Published under the 2-clause BSD license.
  4034. * See license.txt in the OpenLayers distribution or repository for the
  4035. * full text of the license. */
  4036. /**
  4037. * @requires OpenLayers/BaseTypes/Class.js
  4038. */
  4039. /**
  4040. * Class: OpenLayers.Control
  4041. * Controls affect the display or behavior of the map. They allow everything
  4042. * from panning and zooming to displaying a scale indicator. Controls by
  4043. * default are added to the map they are contained within however it is
  4044. * possible to add a control to an external div by passing the div in the
  4045. * options parameter.
  4046. *
  4047. * Example:
  4048. * The following example shows how to add many of the common controls
  4049. * to a map.
  4050. *
  4051. * > var map = new OpenLayers.Map('map', { controls: [] });
  4052. * >
  4053. * > map.addControl(new OpenLayers.Control.PanZoomBar());
  4054. * > map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
  4055. * > map.addControl(new OpenLayers.Control.Permalink());
  4056. * > map.addControl(new OpenLayers.Control.Permalink('permalink'));
  4057. * > map.addControl(new OpenLayers.Control.MousePosition());
  4058. * > map.addControl(new OpenLayers.Control.OverviewMap());
  4059. * > map.addControl(new OpenLayers.Control.KeyboardDefaults());
  4060. *
  4061. * The next code fragment is a quick example of how to intercept
  4062. * shift-mouse click to display the extent of the bounding box
  4063. * dragged out by the user. Usually controls are not created
  4064. * in exactly this manner. See the source for a more complete
  4065. * example:
  4066. *
  4067. * > var control = new OpenLayers.Control();
  4068. * > OpenLayers.Util.extend(control, {
  4069. * > draw: function () {
  4070. * > // this Handler.Box will intercept the shift-mousedown
  4071. * > // before Control.MouseDefault gets to see it
  4072. * > this.box = new OpenLayers.Handler.Box( control,
  4073. * > {"done": this.notice},
  4074. * > {keyMask: OpenLayers.Handler.MOD_SHIFT});
  4075. * > this.box.activate();
  4076. * > },
  4077. * >
  4078. * > notice: function (bounds) {
  4079. * > OpenLayers.Console.userError(bounds);
  4080. * > }
  4081. * > });
  4082. * > map.addControl(control);
  4083. *
  4084. */
  4085. OpenLayers.Control = OpenLayers.Class({
  4086. /**
  4087. * Property: id
  4088. * {String}
  4089. */
  4090. id: null,
  4091. /**
  4092. * Property: map
  4093. * {<OpenLayers.Map>} this gets set in the addControl() function in
  4094. * OpenLayers.Map
  4095. */
  4096. map: null,
  4097. /**
  4098. * APIProperty: div
  4099. * {DOMElement} The element that contains the control, if not present the
  4100. * control is placed inside the map.
  4101. */
  4102. div: null,
  4103. /**
  4104. * APIProperty: type
  4105. * {Number} Controls can have a 'type'. The type determines the type of
  4106. * interactions which are possible with them when they are placed in an
  4107. * <OpenLayers.Control.Panel>.
  4108. */
  4109. type: null,
  4110. /**
  4111. * Property: allowSelection
  4112. * {Boolean} By default, controls do not allow selection, because
  4113. * it may interfere with map dragging. If this is true, OpenLayers
  4114. * will not prevent selection of the control.
  4115. * Default is false.
  4116. */
  4117. allowSelection: false,
  4118. /**
  4119. * Property: displayClass
  4120. * {string} This property is used for CSS related to the drawing of the
  4121. * Control.
  4122. */
  4123. displayClass: "",
  4124. /**
  4125. * APIProperty: title
  4126. * {string} This property is used for showing a tooltip over the
  4127. * Control.
  4128. */
  4129. title: "",
  4130. /**
  4131. * APIProperty: autoActivate
  4132. * {Boolean} Activate the control when it is added to a map. Default is
  4133. * false.
  4134. */
  4135. autoActivate: false,
  4136. /**
  4137. * APIProperty: active
  4138. * {Boolean} The control is active (read-only). Use <activate> and
  4139. * <deactivate> to change control state.
  4140. */
  4141. active: null,
  4142. /**
  4143. * Property: handler
  4144. * {<OpenLayers.Handler>} null
  4145. */
  4146. handler: null,
  4147. /**
  4148. * APIProperty: eventListeners
  4149. * {Object} If set as an option at construction, the eventListeners
  4150. * object will be registered with <OpenLayers.Events.on>. Object
  4151. * structure must be a listeners object as shown in the example for
  4152. * the events.on method.
  4153. */
  4154. eventListeners: null,
  4155. /**
  4156. * APIProperty: events
  4157. * {<OpenLayers.Events>} Events instance for listeners and triggering
  4158. * control specific events.
  4159. *
  4160. * Register a listener for a particular event with the following syntax:
  4161. * (code)
  4162. * control.events.register(type, obj, listener);
  4163. * (end)
  4164. *
  4165. * Listeners will be called with a reference to an event object. The
  4166. * properties of this event depends on exactly what happened.
  4167. *
  4168. * All event objects have at least the following properties:
  4169. * object - {Object} A reference to control.events.object (a reference
  4170. * to the control).
  4171. * element - {DOMElement} A reference to control.events.element (which
  4172. * will be null unless documented otherwise).
  4173. *
  4174. * Supported map event types:
  4175. * activate - Triggered when activated.
  4176. * deactivate - Triggered when deactivated.
  4177. */
  4178. events: null,
  4179. /**
  4180. * Constructor: OpenLayers.Control
  4181. * Create an OpenLayers Control. The options passed as a parameter
  4182. * directly extend the control. For example passing the following:
  4183. *
  4184. * > var control = new OpenLayers.Control({div: myDiv});
  4185. *
  4186. * Overrides the default div attribute value of null.
  4187. *
  4188. * Parameters:
  4189. * options - {Object}
  4190. */
  4191. initialize: function (options) {
  4192. // We do this before the extend so that instances can override
  4193. // className in options.
  4194. this.displayClass =
  4195. this.CLASS_NAME.replace("OpenLayers.", "ol").replace(/\./g, "");
  4196. OpenLayers.Util.extend(this, options);
  4197. this.events = new OpenLayers.Events(this);
  4198. if(this.eventListeners instanceof Object) {
  4199. this.events.on(this.eventListeners);
  4200. }
  4201. if (this.id == null) {
  4202. this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
  4203. }
  4204. },
  4205. /**
  4206. * Method: destroy
  4207. * The destroy method is used to perform any clean up before the control
  4208. * is dereferenced. Typically this is where event listeners are removed
  4209. * to prevent memory leaks.
  4210. */
  4211. destroy: function () {
  4212. if(this.events) {
  4213. if(this.eventListeners) {
  4214. this.events.un(this.eventListeners);
  4215. }
  4216. this.events.destroy();
  4217. this.events = null;
  4218. }
  4219. this.eventListeners = null;
  4220. // eliminate circular references
  4221. if (this.handler) {
  4222. this.handler.destroy();
  4223. this.handler = null;
  4224. }
  4225. if(this.handlers) {
  4226. for(var key in this.handlers) {
  4227. if(this.handlers.hasOwnProperty(key) &&
  4228. typeof this.handlers[key].destroy == "function") {
  4229. this.handlers[key].destroy();
  4230. }
  4231. }
  4232. this.handlers = null;
  4233. }
  4234. if (this.map) {
  4235. this.map.removeControl(this);
  4236. this.map = null;
  4237. }
  4238. this.div = null;
  4239. },
  4240. /**
  4241. * Method: setMap
  4242. * Set the map property for the control. This is done through an accessor
  4243. * so that subclasses can override this and take special action once
  4244. * they have their map variable set.
  4245. *
  4246. * Parameters:
  4247. * map - {<OpenLayers.Map>}
  4248. */
  4249. setMap: function(map) {
  4250. this.map = map;
  4251. if (this.handler) {
  4252. this.handler.setMap(map);
  4253. }
  4254. },
  4255. /**
  4256. * Method: draw
  4257. * The draw method is called when the control is ready to be displayed
  4258. * on the page. If a div has not been created one is created. Controls
  4259. * with a visual component will almost always want to override this method
  4260. * to customize the look of control.
  4261. *
  4262. * Parameters:
  4263. * px - {<OpenLayers.Pixel>} The top-left pixel position of the control
  4264. * or null.
  4265. *
  4266. * Returns:
  4267. * {DOMElement} A reference to the DIV DOMElement containing the control
  4268. */
  4269. draw: function (px) {
  4270. if (this.div == null) {
  4271. this.div = OpenLayers.Util.createDiv(this.id);
  4272. this.div.className = this.displayClass;
  4273. if (!this.allowSelection) {
  4274. this.div.className += " olControlNoSelect";
  4275. this.div.setAttribute("unselectable", "on", 0);
  4276. this.div.onselectstart = OpenLayers.Function.False;
  4277. }
  4278. if (this.title != "") {
  4279. this.div.title = this.title;
  4280. }
  4281. }
  4282. if (px != null) {
  4283. this.position = px.clone();
  4284. }
  4285. this.moveTo(this.position);
  4286. return this.div;
  4287. },
  4288. /**
  4289. * Method: moveTo
  4290. * Sets the left and top style attributes to the passed in pixel
  4291. * coordinates.
  4292. *
  4293. * Parameters:
  4294. * px - {<OpenLayers.Pixel>}
  4295. */
  4296. moveTo: function (px) {
  4297. if ((px != null) && (this.div != null)) {
  4298. this.div.style.left = px.x + "px";
  4299. this.div.style.top = px.y + "px";
  4300. }
  4301. },
  4302. /**
  4303. * APIMethod: activate
  4304. * Explicitly activates a control and it's associated
  4305. * handler if one has been set. Controls can be
  4306. * deactivated by calling the deactivate() method.
  4307. *
  4308. * Returns:
  4309. * {Boolean} True if the control was successfully activated or
  4310. * false if the control was already active.
  4311. */
  4312. activate: function () {
  4313. if (this.active) {
  4314. return false;
  4315. }
  4316. if (this.handler) {
  4317. this.handler.activate();
  4318. }
  4319. this.active = true;
  4320. if(this.map) {
  4321. OpenLayers.Element.addClass(
  4322. this.map.viewPortDiv,
  4323. this.displayClass.replace(/ /g, "") + "Active"
  4324. );
  4325. }
  4326. this.events.triggerEvent("activate");
  4327. return true;
  4328. },
  4329. /**
  4330. * APIMethod: deactivate
  4331. * Deactivates a control and it's associated handler if any. The exact
  4332. * effect of this depends on the control itself.
  4333. *
  4334. * Returns:
  4335. * {Boolean} True if the control was effectively deactivated or false
  4336. * if the control was already inactive.
  4337. */
  4338. deactivate: function () {
  4339. if (this.active) {
  4340. if (this.handler) {
  4341. this.handler.deactivate();
  4342. }
  4343. this.active = false;
  4344. if(this.map) {
  4345. OpenLayers.Element.removeClass(
  4346. this.map.viewPortDiv,
  4347. this.displayClass.replace(/ /g, "") + "Active"
  4348. );
  4349. }
  4350. this.events.triggerEvent("deactivate");
  4351. return true;
  4352. }
  4353. return false;
  4354. },
  4355. CLASS_NAME: "OpenLayers.Control"
  4356. });
  4357. /**
  4358. * Constant: OpenLayers.Control.TYPE_BUTTON
  4359. */
  4360. OpenLayers.Control.TYPE_BUTTON = 1;
  4361. /**
  4362. * Constant: OpenLayers.Control.TYPE_TOGGLE
  4363. */
  4364. OpenLayers.Control.TYPE_TOGGLE = 2;
  4365. /**
  4366. * Constant: OpenLayers.Control.TYPE_TOOL
  4367. */
  4368. OpenLayers.Control.TYPE_TOOL = 3;
  4369. /* ======================================================================
  4370. OpenLayers/Events.js
  4371. ====================================================================== */
  4372. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  4373. * full list of contributors). Published under the 2-clause BSD license.
  4374. * See license.txt in the OpenLayers distribution or repository for the
  4375. * full text of the license. */
  4376. /**
  4377. * @requires OpenLayers/Util.js
  4378. */
  4379. /**
  4380. * Namespace: OpenLayers.Event
  4381. * Utility functions for event handling.
  4382. */
  4383. OpenLayers.Event = {
  4384. /**
  4385. * Property: observers
  4386. * {Object} A hashtable cache of the event observers. Keyed by
  4387. * element._eventCacheID
  4388. */
  4389. observers: false,
  4390. /**
  4391. * Constant: KEY_SPACE
  4392. * {int}
  4393. */
  4394. KEY_SPACE: 32,
  4395. /**
  4396. * Constant: KEY_BACKSPACE
  4397. * {int}
  4398. */
  4399. KEY_BACKSPACE: 8,
  4400. /**
  4401. * Constant: KEY_TAB
  4402. * {int}
  4403. */
  4404. KEY_TAB: 9,
  4405. /**
  4406. * Constant: KEY_RETURN
  4407. * {int}
  4408. */
  4409. KEY_RETURN: 13,
  4410. /**
  4411. * Constant: KEY_ESC
  4412. * {int}
  4413. */
  4414. KEY_ESC: 27,
  4415. /**
  4416. * Constant: KEY_LEFT
  4417. * {int}
  4418. */
  4419. KEY_LEFT: 37,
  4420. /**
  4421. * Constant: KEY_UP
  4422. * {int}
  4423. */
  4424. KEY_UP: 38,
  4425. /**
  4426. * Constant: KEY_RIGHT
  4427. * {int}
  4428. */
  4429. KEY_RIGHT: 39,
  4430. /**
  4431. * Constant: KEY_DOWN
  4432. * {int}
  4433. */
  4434. KEY_DOWN: 40,
  4435. /**
  4436. * Constant: KEY_DELETE
  4437. * {int}
  4438. */
  4439. KEY_DELETE: 46,
  4440. /**
  4441. * Method: element
  4442. * Cross browser event element detection.
  4443. *
  4444. * Parameters:
  4445. * event - {Event}
  4446. *
  4447. * Returns:
  4448. * {DOMElement} The element that caused the event
  4449. */
  4450. element: function(event) {
  4451. return event.target || event.srcElement;
  4452. },
  4453. /**
  4454. * Method: isSingleTouch
  4455. * Determine whether event was caused by a single touch
  4456. *
  4457. * Parameters:
  4458. * event - {Event}
  4459. *
  4460. * Returns:
  4461. * {Boolean}
  4462. */
  4463. isSingleTouch: function(event) {
  4464. return event.touches && event.touches.length == 1;
  4465. },
  4466. /**
  4467. * Method: isMultiTouch
  4468. * Determine whether event was caused by a multi touch
  4469. *
  4470. * Parameters:
  4471. * event - {Event}
  4472. *
  4473. * Returns:
  4474. * {Boolean}
  4475. */
  4476. isMultiTouch: function(event) {
  4477. return event.touches && event.touches.length > 1;
  4478. },
  4479. /**
  4480. * Method: isLeftClick
  4481. * Determine whether event was caused by a left click.
  4482. *
  4483. * Parameters:
  4484. * event - {Event}
  4485. *
  4486. * Returns:
  4487. * {Boolean}
  4488. */
  4489. isLeftClick: function(event) {
  4490. return (((event.which) && (event.which == 1)) ||
  4491. ((event.button) && (event.button == 1)));
  4492. },
  4493. /**
  4494. * Method: isRightClick
  4495. * Determine whether event was caused by a right mouse click.
  4496. *
  4497. * Parameters:
  4498. * event - {Event}
  4499. *
  4500. * Returns:
  4501. * {Boolean}
  4502. */
  4503. isRightClick: function(event) {
  4504. return (((event.which) && (event.which == 3)) ||
  4505. ((event.button) && (event.button == 2)));
  4506. },
  4507. /**
  4508. * Method: stop
  4509. * Stops an event from propagating.
  4510. *
  4511. * Parameters:
  4512. * event - {Event}
  4513. * allowDefault - {Boolean} If true, we stop the event chain but
  4514. * still allow the default browser behaviour (text selection,
  4515. * radio-button clicking, etc). Default is false.
  4516. */
  4517. stop: function(event, allowDefault) {
  4518. if (!allowDefault) {
  4519. if (event.preventDefault) {
  4520. event.preventDefault();
  4521. } else {
  4522. event.returnValue = false;
  4523. }
  4524. }
  4525. if (event.stopPropagation) {
  4526. event.stopPropagation();
  4527. } else {
  4528. event.cancelBubble = true;
  4529. }
  4530. },
  4531. /**
  4532. * Method: findElement
  4533. *
  4534. * Parameters:
  4535. * event - {Event}
  4536. * tagName - {String}
  4537. *
  4538. * Returns:
  4539. * {DOMElement} The first node with the given tagName, starting from the
  4540. * node the event was triggered on and traversing the DOM upwards
  4541. */
  4542. findElement: function(event, tagName) {
  4543. var element = OpenLayers.Event.element(event);
  4544. while (element.parentNode && (!element.tagName ||
  4545. (element.tagName.toUpperCase() != tagName.toUpperCase()))){
  4546. element = element.parentNode;
  4547. }
  4548. return element;
  4549. },
  4550. /**
  4551. * Method: observe
  4552. *
  4553. * Parameters:
  4554. * elementParam - {DOMElement || String}
  4555. * name - {String}
  4556. * observer - {function}
  4557. * useCapture - {Boolean}
  4558. */
  4559. observe: function(elementParam, name, observer, useCapture) {
  4560. var element = OpenLayers.Util.getElement(elementParam);
  4561. useCapture = useCapture || false;
  4562. if (name == 'keypress' &&
  4563. (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
  4564. || element.attachEvent)) {
  4565. name = 'keydown';
  4566. }
  4567. //if observers cache has not yet been created, create it
  4568. if (!this.observers) {
  4569. this.observers = {};
  4570. }
  4571. //if not already assigned, make a new unique cache ID
  4572. if (!element._eventCacheID) {
  4573. var idPrefix = "eventCacheID_";
  4574. if (element.id) {
  4575. idPrefix = element.id + "_" + idPrefix;
  4576. }
  4577. element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);
  4578. }
  4579. var cacheID = element._eventCacheID;
  4580. //if there is not yet a hash entry for this element, add one
  4581. if (!this.observers[cacheID]) {
  4582. this.observers[cacheID] = [];
  4583. }
  4584. //add a new observer to this element's list
  4585. this.observers[cacheID].push({
  4586. 'element': element,
  4587. 'name': name,
  4588. 'observer': observer,
  4589. 'useCapture': useCapture
  4590. });
  4591. //add the actual browser event listener
  4592. if (element.addEventListener) {
  4593. element.addEventListener(name, observer, useCapture);
  4594. } else if (element.attachEvent) {
  4595. element.attachEvent('on' + name, observer);
  4596. }
  4597. },
  4598. /**
  4599. * Method: stopObservingElement
  4600. * Given the id of an element to stop observing, cycle through the
  4601. * element's cached observers, calling stopObserving on each one,
  4602. * skipping those entries which can no longer be removed.
  4603. *
  4604. * parameters:
  4605. * elementParam - {DOMElement || String}
  4606. */
  4607. stopObservingElement: function(elementParam) {
  4608. var element = OpenLayers.Util.getElement(elementParam);
  4609. var cacheID = element._eventCacheID;
  4610. this._removeElementObservers(OpenLayers.Event.observers[cacheID]);
  4611. },
  4612. /**
  4613. * Method: _removeElementObservers
  4614. *
  4615. * Parameters:
  4616. * elementObservers - {Array(Object)} Array of (element, name,
  4617. * observer, usecapture) objects,
  4618. * taken directly from hashtable
  4619. */
  4620. _removeElementObservers: function(elementObservers) {
  4621. if (elementObservers) {
  4622. for(var i = elementObservers.length-1; i >= 0; i--) {
  4623. var entry = elementObservers[i];
  4624. var args = new Array(entry.element,
  4625. entry.name,
  4626. entry.observer,
  4627. entry.useCapture);
  4628. var removed = OpenLayers.Event.stopObserving.apply(this, args);
  4629. }
  4630. }
  4631. },
  4632. /**
  4633. * Method: stopObserving
  4634. *
  4635. * Parameters:
  4636. * elementParam - {DOMElement || String}
  4637. * name - {String}
  4638. * observer - {function}
  4639. * useCapture - {Boolean}
  4640. *
  4641. * Returns:
  4642. * {Boolean} Whether or not the event observer was removed
  4643. */
  4644. stopObserving: function(elementParam, name, observer, useCapture) {
  4645. useCapture = useCapture || false;
  4646. var element = OpenLayers.Util.getElement(elementParam);
  4647. var cacheID = element._eventCacheID;
  4648. if (name == 'keypress') {
  4649. if ( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||
  4650. element.detachEvent) {
  4651. name = 'keydown';
  4652. }
  4653. }
  4654. // find element's entry in this.observers cache and remove it
  4655. var foundEntry = false;
  4656. var elementObservers = OpenLayers.Event.observers[cacheID];
  4657. if (elementObservers) {
  4658. // find the specific event type in the element's list
  4659. var i=0;
  4660. while(!foundEntry && i < elementObservers.length) {
  4661. var cacheEntry = elementObservers[i];
  4662. if ((cacheEntry.name == name) &&
  4663. (cacheEntry.observer == observer) &&
  4664. (cacheEntry.useCapture == useCapture)) {
  4665. elementObservers.splice(i, 1);
  4666. if (elementObservers.length == 0) {
  4667. delete OpenLayers.Event.observers[cacheID];
  4668. }
  4669. foundEntry = true;
  4670. break;
  4671. }
  4672. i++;
  4673. }
  4674. }
  4675. //actually remove the event listener from browser
  4676. if (foundEntry) {
  4677. if (element.removeEventListener) {
  4678. element.removeEventListener(name, observer, useCapture);
  4679. } else if (element && element.detachEvent) {
  4680. element.detachEvent('on' + name, observer);
  4681. }
  4682. }
  4683. return foundEntry;
  4684. },
  4685. /**
  4686. * Method: unloadCache
  4687. * Cycle through all the element entries in the events cache and call
  4688. * stopObservingElement on each.
  4689. */
  4690. unloadCache: function() {
  4691. // check for OpenLayers.Event before checking for observers, because
  4692. // OpenLayers.Event may be undefined in IE if no map instance was
  4693. // created
  4694. if (OpenLayers.Event && OpenLayers.Event.observers) {
  4695. for (var cacheID in OpenLayers.Event.observers) {
  4696. var elementObservers = OpenLayers.Event.observers[cacheID];
  4697. OpenLayers.Event._removeElementObservers.apply(this,
  4698. [elementObservers]);
  4699. }
  4700. OpenLayers.Event.observers = false;
  4701. }
  4702. },
  4703. CLASS_NAME: "OpenLayers.Event"
  4704. };
  4705. /* prevent memory leaks in IE */
  4706. OpenLayers.Event.observe(window, 'unload', OpenLayers.Event.unloadCache, false);
  4707. /**
  4708. * Class: OpenLayers.Events
  4709. */
  4710. OpenLayers.Events = OpenLayers.Class({
  4711. /**
  4712. * Constant: BROWSER_EVENTS
  4713. * {Array(String)} supported events
  4714. */
  4715. BROWSER_EVENTS: [
  4716. "mouseover", "mouseout",
  4717. "mousedown", "mouseup", "mousemove",
  4718. "click", "dblclick", "rightclick", "dblrightclick",
  4719. "resize", "focus", "blur",
  4720. "touchstart", "touchmove", "touchend",
  4721. "keydown"
  4722. ],
  4723. /**
  4724. * Property: listeners
  4725. * {Object} Hashtable of Array(Function): events listener functions
  4726. */
  4727. listeners: null,
  4728. /**
  4729. * Property: object
  4730. * {Object} the code object issuing application events
  4731. */
  4732. object: null,
  4733. /**
  4734. * Property: element
  4735. * {DOMElement} the DOM element receiving browser events
  4736. */
  4737. element: null,
  4738. /**
  4739. * Property: eventHandler
  4740. * {Function} bound event handler attached to elements
  4741. */
  4742. eventHandler: null,
  4743. /**
  4744. * APIProperty: fallThrough
  4745. * {Boolean}
  4746. */
  4747. fallThrough: null,
  4748. /**
  4749. * APIProperty: includeXY
  4750. * {Boolean} Should the .xy property automatically be created for browser
  4751. * mouse events? In general, this should be false. If it is true, then
  4752. * mouse events will automatically generate a '.xy' property on the
  4753. * event object that is passed. (Prior to OpenLayers 2.7, this was true
  4754. * by default.) Otherwise, you can call the getMousePosition on the
  4755. * relevant events handler on the object available via the 'evt.object'
  4756. * property of the evt object. So, for most events, you can call:
  4757. * function named(evt) {
  4758. * this.xy = this.object.events.getMousePosition(evt)
  4759. * }
  4760. *
  4761. * This option typically defaults to false for performance reasons:
  4762. * when creating an events object whose primary purpose is to manage
  4763. * relatively positioned mouse events within a div, it may make
  4764. * sense to set it to true.
  4765. *
  4766. * This option is also used to control whether the events object caches
  4767. * offsets. If this is false, it will not: the reason for this is that
  4768. * it is only expected to be called many times if the includeXY property
  4769. * is set to true. If you set this to true, you are expected to clear
  4770. * the offset cache manually (using this.clearMouseCache()) if:
  4771. * the border of the element changes
  4772. * the location of the element in the page changes
  4773. */
  4774. includeXY: false,
  4775. /**
  4776. * APIProperty: extensions
  4777. * {Object} Event extensions registered with this instance. Keys are
  4778. * event types, values are {OpenLayers.Events.*} extension instances or
  4779. * {Boolean} for events that an instantiated extension provides in
  4780. * addition to the one it was created for.
  4781. *
  4782. * Extensions create an event in addition to browser events, which usually
  4783. * fires when a sequence of browser events is completed. Extensions are
  4784. * automatically instantiated when a listener is registered for an event
  4785. * provided by an extension.
  4786. *
  4787. * Extensions are created in the <OpenLayers.Events> namespace using
  4788. * <OpenLayers.Class>, and named after the event they provide.
  4789. * The constructor receives the target <OpenLayers.Events> instance as
  4790. * argument. Extensions that need to capture browser events before they
  4791. * propagate can register their listeners events using <register>, with
  4792. * {extension: true} as 4th argument.
  4793. *
  4794. * If an extension creates more than one event, an alias for each event
  4795. * type should be created and reference the same class. The constructor
  4796. * should set a reference in the target's extensions registry to itself.
  4797. *
  4798. * Below is a minimal extension that provides the "foostart" and "fooend"
  4799. * event types, which replace the native "click" event type if clicked on
  4800. * an element with the css class "foo":
  4801. *
  4802. * (code)
  4803. * OpenLayers.Events.foostart = OpenLayers.Class({
  4804. * initialize: function(target) {
  4805. * this.target = target;
  4806. * this.target.register("click", this, this.doStuff, {extension: true});
  4807. * // only required if extension provides more than one event type
  4808. * this.target.extensions["foostart"] = true;
  4809. * this.target.extensions["fooend"] = true;
  4810. * },
  4811. * destroy: function() {
  4812. * var target = this.target;
  4813. * target.unregister("click", this, this.doStuff);
  4814. * delete this.target;
  4815. * // only required if extension provides more than one event type
  4816. * delete target.extensions["foostart"];
  4817. * delete target.extensions["fooend"];
  4818. * },
  4819. * doStuff: function(evt) {
  4820. * var propagate = true;
  4821. * if (OpenLayers.Event.element(evt).className === "foo") {
  4822. * propagate = false;
  4823. * var target = this.target;
  4824. * target.triggerEvent("foostart");
  4825. * window.setTimeout(function() {
  4826. * target.triggerEvent("fooend");
  4827. * }, 1000);
  4828. * }
  4829. * return propagate;
  4830. * }
  4831. * });
  4832. * // only required if extension provides more than one event type
  4833. * OpenLayers.Events.fooend = OpenLayers.Events.foostart;
  4834. * (end)
  4835. *
  4836. */
  4837. extensions: null,
  4838. /**
  4839. * Property: extensionCount
  4840. * {Object} Keys are event types (like in <listeners>), values are the
  4841. * number of extension listeners for each event type.
  4842. */
  4843. extensionCount: null,
  4844. /**
  4845. * Method: clearMouseListener
  4846. * A version of <clearMouseCache> that is bound to this instance so that
  4847. * it can be used with <OpenLayers.Event.observe> and
  4848. * <OpenLayers.Event.stopObserving>.
  4849. */
  4850. clearMouseListener: null,
  4851. /**
  4852. * Constructor: OpenLayers.Events
  4853. * Construct an OpenLayers.Events object.
  4854. *
  4855. * Parameters:
  4856. * object - {Object} The js object to which this Events object is being added
  4857. * element - {DOMElement} A dom element to respond to browser events
  4858. * eventTypes - {Array(String)} Deprecated. Array of custom application
  4859. * events. A listener may be registered for any named event, regardless
  4860. * of the values provided here.
  4861. * fallThrough - {Boolean} Allow events to fall through after these have
  4862. * been handled?
  4863. * options - {Object} Options for the events object.
  4864. */
  4865. initialize: function (object, element, eventTypes, fallThrough, options) {
  4866. OpenLayers.Util.extend(this, options);
  4867. this.object = object;
  4868. this.fallThrough = fallThrough;
  4869. this.listeners = {};
  4870. this.extensions = {};
  4871. this.extensionCount = {};
  4872. // if a dom element is specified, add a listeners list
  4873. // for browser events on the element and register them
  4874. if (element != null) {
  4875. this.attachToElement(element);
  4876. }
  4877. },
  4878. /**
  4879. * APIMethod: destroy
  4880. */
  4881. destroy: function () {
  4882. for (var e in this.extensions) {
  4883. if (typeof this.extensions[e] !== "boolean") {
  4884. this.extensions[e].destroy();
  4885. }
  4886. }
  4887. this.extensions = null;
  4888. if (this.element) {
  4889. OpenLayers.Event.stopObservingElement(this.element);
  4890. if(this.element.hasScrollEvent) {
  4891. OpenLayers.Event.stopObserving(
  4892. window, "scroll", this.clearMouseListener
  4893. );
  4894. }
  4895. }
  4896. this.element = null;
  4897. this.listeners = null;
  4898. this.object = null;
  4899. this.fallThrough = null;
  4900. this.eventHandler = null;
  4901. },
  4902. /**
  4903. * APIMethod: addEventType
  4904. * Deprecated. Any event can be triggered without adding it first.
  4905. *
  4906. * Parameters:
  4907. * eventName - {String}
  4908. */
  4909. addEventType: function(eventName) {
  4910. },
  4911. /**
  4912. * Method: attachToElement
  4913. *
  4914. * Parameters:
  4915. * element - {HTMLDOMElement} a DOM element to attach browser events to
  4916. */
  4917. attachToElement: function (element) {
  4918. if (this.element) {
  4919. OpenLayers.Event.stopObservingElement(this.element);
  4920. } else {
  4921. // keep a bound copy of handleBrowserEvent() so that we can
  4922. // pass the same function to both Event.observe() and .stopObserving()
  4923. this.eventHandler = OpenLayers.Function.bindAsEventListener(
  4924. this.handleBrowserEvent, this
  4925. );
  4926. // to be used with observe and stopObserving
  4927. this.clearMouseListener = OpenLayers.Function.bind(
  4928. this.clearMouseCache, this
  4929. );
  4930. }
  4931. this.element = element;
  4932. for (var i = 0, len = this.BROWSER_EVENTS.length; i < len; i++) {
  4933. // register the event cross-browser
  4934. OpenLayers.Event.observe(
  4935. element, this.BROWSER_EVENTS[i], this.eventHandler
  4936. );
  4937. }
  4938. // disable dragstart in IE so that mousedown/move/up works normally
  4939. OpenLayers.Event.observe(element, "dragstart", OpenLayers.Event.stop);
  4940. },
  4941. /**
  4942. * APIMethod: on
  4943. * Convenience method for registering listeners with a common scope.
  4944. * Internally, this method calls <register> as shown in the examples
  4945. * below.
  4946. *
  4947. * Example use:
  4948. * (code)
  4949. * // register a single listener for the "loadstart" event
  4950. * events.on({"loadstart": loadStartListener});
  4951. *
  4952. * // this is equivalent to the following
  4953. * events.register("loadstart", undefined, loadStartListener);
  4954. *
  4955. * // register multiple listeners to be called with the same `this` object
  4956. * events.on({
  4957. * "loadstart": loadStartListener,
  4958. * "loadend": loadEndListener,
  4959. * scope: object
  4960. * });
  4961. *
  4962. * // this is equivalent to the following
  4963. * events.register("loadstart", object, loadStartListener);
  4964. * events.register("loadend", object, loadEndListener);
  4965. * (end)
  4966. *
  4967. * Parameters:
  4968. * object - {Object}
  4969. */
  4970. on: function(object) {
  4971. for(var type in object) {
  4972. if(type != "scope" && object.hasOwnProperty(type)) {
  4973. this.register(type, object.scope, object[type]);
  4974. }
  4975. }
  4976. },
  4977. /**
  4978. * APIMethod: register
  4979. * Register an event on the events object.
  4980. *
  4981. * When the event is triggered, the 'func' function will be called, in the
  4982. * context of 'obj'. Imagine we were to register an event, specifying an
  4983. * OpenLayers.Bounds Object as 'obj'. When the event is triggered, the
  4984. * context in the callback function will be our Bounds object. This means
  4985. * that within our callback function, we can access the properties and
  4986. * methods of the Bounds object through the "this" variable. So our
  4987. * callback could execute something like:
  4988. * : leftStr = "Left: " + this.left;
  4989. *
  4990. * or
  4991. *
  4992. * : centerStr = "Center: " + this.getCenterLonLat();
  4993. *
  4994. * Parameters:
  4995. * type - {String} Name of the event to register
  4996. * obj - {Object} The object to bind the context to for the callback#.
  4997. * If no object is specified, default is the Events's 'object' property.
  4998. * func - {Function} The callback function. If no callback is
  4999. * specified, this function does nothing.
  5000. * priority - {Boolean|Object} If true, adds the new listener to the
  5001. * *front* of the events queue instead of to the end.
  5002. *
  5003. * Valid options for priority:
  5004. * extension - {Boolean} If true, then the event will be registered as
  5005. * extension event. Extension events are handled before all other
  5006. * events.
  5007. */
  5008. register: function (type, obj, func, priority) {
  5009. if (type in OpenLayers.Events && !this.extensions[type]) {
  5010. this.extensions[type] = new OpenLayers.Events[type](this);
  5011. }
  5012. if (func != null) {
  5013. if (obj == null) {
  5014. obj = this.object;
  5015. }
  5016. var listeners = this.listeners[type];
  5017. if (!listeners) {
  5018. listeners = [];
  5019. this.listeners[type] = listeners;
  5020. this.extensionCount[type] = 0;
  5021. }
  5022. var listener = {obj: obj, func: func};
  5023. if (priority) {
  5024. listeners.splice(this.extensionCount[type], 0, listener);
  5025. if (typeof priority === "object" && priority.extension) {
  5026. this.extensionCount[type]++;
  5027. }
  5028. } else {
  5029. listeners.push(listener);
  5030. }
  5031. }
  5032. },
  5033. /**
  5034. * APIMethod: registerPriority
  5035. * Same as register() but adds the new listener to the *front* of the
  5036. * events queue instead of to the end.
  5037. *
  5038. * TODO: get rid of this in 3.0 - Decide whether listeners should be
  5039. * called in the order they were registered or in reverse order.
  5040. *
  5041. *
  5042. * Parameters:
  5043. * type - {String} Name of the event to register
  5044. * obj - {Object} The object to bind the context to for the callback#.
  5045. * If no object is specified, default is the Events's
  5046. * 'object' property.
  5047. * func - {Function} The callback function. If no callback is
  5048. * specified, this function does nothing.
  5049. */
  5050. registerPriority: function (type, obj, func) {
  5051. this.register(type, obj, func, true);
  5052. },
  5053. /**
  5054. * APIMethod: un
  5055. * Convenience method for unregistering listeners with a common scope.
  5056. * Internally, this method calls <unregister> as shown in the examples
  5057. * below.
  5058. *
  5059. * Example use:
  5060. * (code)
  5061. * // unregister a single listener for the "loadstart" event
  5062. * events.un({"loadstart": loadStartListener});
  5063. *
  5064. * // this is equivalent to the following
  5065. * events.unregister("loadstart", undefined, loadStartListener);
  5066. *
  5067. * // unregister multiple listeners with the same `this` object
  5068. * events.un({
  5069. * "loadstart": loadStartListener,
  5070. * "loadend": loadEndListener,
  5071. * scope: object
  5072. * });
  5073. *
  5074. * // this is equivalent to the following
  5075. * events.unregister("loadstart", object, loadStartListener);
  5076. * events.unregister("loadend", object, loadEndListener);
  5077. * (end)
  5078. */
  5079. un: function(object) {
  5080. for(var type in object) {
  5081. if(type != "scope" && object.hasOwnProperty(type)) {
  5082. this.unregister(type, object.scope, object[type]);
  5083. }
  5084. }
  5085. },
  5086. /**
  5087. * APIMethod: unregister
  5088. *
  5089. * Parameters:
  5090. * type - {String}
  5091. * obj - {Object} If none specified, defaults to this.object
  5092. * func - {Function}
  5093. */
  5094. unregister: function (type, obj, func) {
  5095. if (obj == null) {
  5096. obj = this.object;
  5097. }
  5098. var listeners = this.listeners[type];
  5099. if (listeners != null) {
  5100. for (var i=0, len=listeners.length; i<len; i++) {
  5101. if (listeners[i].obj == obj && listeners[i].func == func) {
  5102. listeners.splice(i, 1);
  5103. break;
  5104. }
  5105. }
  5106. }
  5107. },
  5108. /**
  5109. * Method: remove
  5110. * Remove all listeners for a given event type. If type is not registered,
  5111. * does nothing.
  5112. *
  5113. * Parameters:
  5114. * type - {String}
  5115. */
  5116. remove: function(type) {
  5117. if (this.listeners[type] != null) {
  5118. this.listeners[type] = [];
  5119. }
  5120. },
  5121. /**
  5122. * APIMethod: triggerEvent
  5123. * Trigger a specified registered event.
  5124. *
  5125. * Parameters:
  5126. * type - {String}
  5127. * evt - {Event}
  5128. *
  5129. * Returns:
  5130. * {Boolean} The last listener return. If a listener returns false, the
  5131. * chain of listeners will stop getting called.
  5132. */
  5133. triggerEvent: function (type, evt) {
  5134. var listeners = this.listeners[type];
  5135. // fast path
  5136. if(!listeners || listeners.length == 0) {
  5137. return undefined;
  5138. }
  5139. // prep evt object with object & div references
  5140. if (evt == null) {
  5141. evt = {};
  5142. }
  5143. evt.object = this.object;
  5144. evt.element = this.element;
  5145. if(!evt.type) {
  5146. evt.type = type;
  5147. }
  5148. // execute all callbacks registered for specified type
  5149. // get a clone of the listeners array to
  5150. // allow for splicing during callbacks
  5151. listeners = listeners.slice();
  5152. var continueChain;
  5153. for (var i=0, len=listeners.length; i<len; i++) {
  5154. var callback = listeners[i];
  5155. // bind the context to callback.obj
  5156. continueChain = callback.func.apply(callback.obj, [evt]);
  5157. if ((continueChain != undefined) && (continueChain == false)) {
  5158. // if callback returns false, execute no more callbacks.
  5159. break;
  5160. }
  5161. }
  5162. // don't fall through to other DOM elements
  5163. if (!this.fallThrough) {
  5164. OpenLayers.Event.stop(evt, true);
  5165. }
  5166. return continueChain;
  5167. },
  5168. /**
  5169. * Method: handleBrowserEvent
  5170. * Basically just a wrapper to the triggerEvent() function, but takes
  5171. * care to set a property 'xy' on the event with the current mouse
  5172. * position.
  5173. *
  5174. * Parameters:
  5175. * evt - {Event}
  5176. */
  5177. handleBrowserEvent: function (evt) {
  5178. var type = evt.type, listeners = this.listeners[type];
  5179. if(!listeners || listeners.length == 0) {
  5180. // noone's listening, bail out
  5181. return;
  5182. }
  5183. // add clientX & clientY to all events - corresponds to average x, y
  5184. var touches = evt.touches;
  5185. if (touches && touches[0]) {
  5186. var x = 0;
  5187. var y = 0;
  5188. var num = touches.length;
  5189. var touch;
  5190. for (var i=0; i<num; ++i) {
  5191. touch = touches[i];
  5192. x += touch.clientX;
  5193. y += touch.clientY;
  5194. }
  5195. evt.clientX = x / num;
  5196. evt.clientY = y / num;
  5197. }
  5198. if (this.includeXY) {
  5199. evt.xy = this.getMousePosition(evt);
  5200. }
  5201. this.triggerEvent(type, evt);
  5202. },
  5203. /**
  5204. * APIMethod: clearMouseCache
  5205. * Clear cached data about the mouse position. This should be called any
  5206. * time the element that events are registered on changes position
  5207. * within the page.
  5208. */
  5209. clearMouseCache: function() {
  5210. this.element.scrolls = null;
  5211. this.element.lefttop = null;
  5212. // OpenLayers.Util.pagePosition needs to use
  5213. // element.getBoundingClientRect to correctly calculate the offsets
  5214. // for the iPhone, but once the page is scrolled, getBoundingClientRect
  5215. // returns incorrect offsets. So our best bet is to not invalidate the
  5216. // offsets once we have them, and hope that the page was not scrolled
  5217. // when we did the initial calculation.
  5218. var body = document.body;
  5219. if (body && !((body.scrollTop != 0 || body.scrollLeft != 0) &&
  5220. navigator.userAgent.match(/iPhone/i))) {
  5221. this.element.offsets = null;
  5222. }
  5223. },
  5224. /**
  5225. * Method: getMousePosition
  5226. *
  5227. * Parameters:
  5228. * evt - {Event}
  5229. *
  5230. * Returns:
  5231. * {<OpenLayers.Pixel>} The current xy coordinate of the mouse, adjusted
  5232. * for offsets
  5233. */
  5234. getMousePosition: function (evt) {
  5235. if (!this.includeXY) {
  5236. this.clearMouseCache();
  5237. } else if (!this.element.hasScrollEvent) {
  5238. OpenLayers.Event.observe(window, "scroll", this.clearMouseListener);
  5239. this.element.hasScrollEvent = true;
  5240. }
  5241. if (!this.element.scrolls) {
  5242. var viewportElement = OpenLayers.Util.getViewportElement();
  5243. this.element.scrolls = [
  5244. viewportElement.scrollLeft,
  5245. viewportElement.scrollTop
  5246. ];
  5247. }
  5248. if (!this.element.lefttop) {
  5249. this.element.lefttop = [
  5250. (document.documentElement.clientLeft || 0),
  5251. (document.documentElement.clientTop || 0)
  5252. ];
  5253. }
  5254. if (!this.element.offsets) {
  5255. this.element.offsets = OpenLayers.Util.pagePosition(this.element);
  5256. }
  5257. return new OpenLayers.Pixel(
  5258. (evt.clientX + this.element.scrolls[0]) - this.element.offsets[0]
  5259. - this.element.lefttop[0],
  5260. (evt.clientY + this.element.scrolls[1]) - this.element.offsets[1]
  5261. - this.element.lefttop[1]
  5262. );
  5263. },
  5264. CLASS_NAME: "OpenLayers.Events"
  5265. });
  5266. /* ======================================================================
  5267. OpenLayers/Events/buttonclick.js
  5268. ====================================================================== */
  5269. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  5270. * full list of contributors). Published under the 2-clause BSD license.
  5271. * See license.txt in the OpenLayers distribution or repository for the
  5272. * full text of the license. */
  5273. /**
  5274. * @requires OpenLayers/Events.js
  5275. */
  5276. /**
  5277. * Class: OpenLayers.Events.buttonclick
  5278. * Extension event type for handling buttons on top of a dom element. This
  5279. * event type fires "buttonclick" on its <target> when a button was
  5280. * clicked. Buttons are detected by the "olButton" class.
  5281. *
  5282. * This event type makes sure that button clicks do not interfere with other
  5283. * events that are registered on the same <element>.
  5284. *
  5285. * Event types provided by this extension:
  5286. * - *buttonclick* Triggered when a button is clicked. Listeners receive an
  5287. * object with a *buttonElement* property referencing the dom element of
  5288. * the clicked button, and an *buttonXY* property with the click position
  5289. * relative to the button.
  5290. */
  5291. OpenLayers.Events.buttonclick = OpenLayers.Class({
  5292. /**
  5293. * Property: target
  5294. * {<OpenLayers.Events>} The events instance that the buttonclick event will
  5295. * be triggered on.
  5296. */
  5297. target: null,
  5298. /**
  5299. * Property: events
  5300. * {Array} Events to observe and conditionally stop from propagating when
  5301. * an element with the olButton class (or its olAlphaImg child) is
  5302. * clicked.
  5303. */
  5304. events: [
  5305. 'mousedown', 'mouseup', 'click', 'dblclick',
  5306. 'touchstart', 'touchmove', 'touchend', 'keydown'
  5307. ],
  5308. /**
  5309. * Property: startRegEx
  5310. * {RegExp} Regular expression to test Event.type for events that start
  5311. * a buttonclick sequence.
  5312. */
  5313. startRegEx: /^mousedown|touchstart$/,
  5314. /**
  5315. * Property: cancelRegEx
  5316. * {RegExp} Regular expression to test Event.type for events that cancel
  5317. * a buttonclick sequence.
  5318. */
  5319. cancelRegEx: /^touchmove$/,
  5320. /**
  5321. * Property: completeRegEx
  5322. * {RegExp} Regular expression to test Event.type for events that complete
  5323. * a buttonclick sequence.
  5324. */
  5325. completeRegEx: /^mouseup|touchend$/,
  5326. /**
  5327. * Property: startEvt
  5328. * {Event} The event that started the click sequence
  5329. */
  5330. /**
  5331. * Constructor: OpenLayers.Events.buttonclick
  5332. * Construct a buttonclick event type. Applications are not supposed to
  5333. * create instances of this class - they are created on demand by
  5334. * <OpenLayers.Events> instances.
  5335. *
  5336. * Parameters:
  5337. * target - {<OpenLayers.Events>} The events instance that the buttonclick
  5338. * event will be triggered on.
  5339. */
  5340. initialize: function(target) {
  5341. this.target = target;
  5342. for (var i=this.events.length-1; i>=0; --i) {
  5343. this.target.register(this.events[i], this, this.buttonClick, {
  5344. extension: true
  5345. });
  5346. }
  5347. },
  5348. /**
  5349. * Method: destroy
  5350. */
  5351. destroy: function() {
  5352. for (var i=this.events.length-1; i>=0; --i) {
  5353. this.target.unregister(this.events[i], this, this.buttonClick);
  5354. }
  5355. delete this.target;
  5356. },
  5357. /**
  5358. * Method: getPressedButton
  5359. * Get the pressed button, if any. Returns undefined if no button
  5360. * was pressed.
  5361. *
  5362. * Arguments:
  5363. * element - {DOMElement} The event target.
  5364. *
  5365. * Returns:
  5366. * {DOMElement} The button element, or undefined.
  5367. */
  5368. getPressedButton: function(element) {
  5369. var depth = 3, // limit the search depth
  5370. button;
  5371. do {
  5372. if(OpenLayers.Element.hasClass(element, "olButton")) {
  5373. // hit!
  5374. button = element;
  5375. break;
  5376. }
  5377. element = element.parentNode;
  5378. } while(--depth > 0 && element);
  5379. return button;
  5380. },
  5381. /**
  5382. * Method: buttonClick
  5383. * Check if a button was clicked, and fire the buttonclick event
  5384. *
  5385. * Parameters:
  5386. * evt - {Event}
  5387. */
  5388. buttonClick: function(evt) {
  5389. var propagate = true,
  5390. element = OpenLayers.Event.element(evt);
  5391. if (element && (OpenLayers.Event.isLeftClick(evt) || !~evt.type.indexOf("mouse"))) {
  5392. // was a button pressed?
  5393. var button = this.getPressedButton(element);
  5394. if (button) {
  5395. if (evt.type === "keydown") {
  5396. switch (evt.keyCode) {
  5397. case OpenLayers.Event.KEY_RETURN:
  5398. case OpenLayers.Event.KEY_SPACE:
  5399. this.target.triggerEvent("buttonclick", {
  5400. buttonElement: button
  5401. });
  5402. OpenLayers.Event.stop(evt);
  5403. propagate = false;
  5404. break;
  5405. }
  5406. } else if (this.startEvt) {
  5407. if (this.completeRegEx.test(evt.type)) {
  5408. var pos = OpenLayers.Util.pagePosition(button);
  5409. this.target.triggerEvent("buttonclick", {
  5410. buttonElement: button,
  5411. buttonXY: {
  5412. x: this.startEvt.clientX - pos[0],
  5413. y: this.startEvt.clientY - pos[1]
  5414. }
  5415. });
  5416. }
  5417. if (this.cancelRegEx.test(evt.type)) {
  5418. delete this.startEvt;
  5419. }
  5420. OpenLayers.Event.stop(evt);
  5421. propagate = false;
  5422. }
  5423. if (this.startRegEx.test(evt.type)) {
  5424. this.startEvt = evt;
  5425. OpenLayers.Event.stop(evt);
  5426. propagate = false;
  5427. }
  5428. } else {
  5429. delete this.startEvt;
  5430. }
  5431. }
  5432. return propagate;
  5433. }
  5434. });
  5435. /* ======================================================================
  5436. OpenLayers/Control/OverviewMap.js
  5437. ====================================================================== */
  5438. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  5439. * full list of contributors). Published under the 2-clause BSD license.
  5440. * See license.txt in the OpenLayers distribution or repository for the
  5441. * full text of the license. */
  5442. /**
  5443. * @requires OpenLayers/Control.js
  5444. * @requires OpenLayers/BaseTypes.js
  5445. * @requires OpenLayers/Events/buttonclick.js
  5446. */
  5447. /**
  5448. * Class: OpenLayers.Control.OverviewMap
  5449. * The OverMap control creates a small overview map, useful to display the
  5450. * extent of a zoomed map and your main map and provide additional
  5451. * navigation options to the User. By default the overview map is drawn in
  5452. * the lower right corner of the main map. Create a new overview map with the
  5453. * <OpenLayers.Control.OverviewMap> constructor.
  5454. *
  5455. * Inherits from:
  5456. * - <OpenLayers.Control>
  5457. */
  5458. OpenLayers.Control.OverviewMap = OpenLayers.Class(OpenLayers.Control, {
  5459. /**
  5460. * Property: element
  5461. * {DOMElement} The DOM element that contains the overview map
  5462. */
  5463. element: null,
  5464. /**
  5465. * APIProperty: ovmap
  5466. * {<OpenLayers.Map>} A reference to the overview map itself.
  5467. */
  5468. ovmap: null,
  5469. /**
  5470. * APIProperty: size
  5471. * {<OpenLayers.Size>} The overvew map size in pixels. Note that this is
  5472. * the size of the map itself - the element that contains the map (default
  5473. * class name olControlOverviewMapElement) may have padding or other style
  5474. * attributes added via CSS.
  5475. */
  5476. size: {w: 180, h: 90},
  5477. /**
  5478. * APIProperty: layers
  5479. * {Array(<OpenLayers.Layer>)} Ordered list of layers in the overview map.
  5480. * If none are sent at construction, the base layer for the main map is used.
  5481. */
  5482. layers: null,
  5483. /**
  5484. * APIProperty: minRectSize
  5485. * {Integer} The minimum width or height (in pixels) of the extent
  5486. * rectangle on the overview map. When the extent rectangle reaches
  5487. * this size, it will be replaced depending on the value of the
  5488. * <minRectDisplayClass> property. Default is 15 pixels.
  5489. */
  5490. minRectSize: 15,
  5491. /**
  5492. * APIProperty: minRectDisplayClass
  5493. * {String} Replacement style class name for the extent rectangle when
  5494. * <minRectSize> is reached. This string will be suffixed on to the
  5495. * displayClass. Default is "RectReplacement".
  5496. *
  5497. * Example CSS declaration:
  5498. * (code)
  5499. * .olControlOverviewMapRectReplacement {
  5500. * overflow: hidden;
  5501. * cursor: move;
  5502. * background-image: url("img/overview_replacement.gif");
  5503. * background-repeat: no-repeat;
  5504. * background-position: center;
  5505. * }
  5506. * (end)
  5507. */
  5508. minRectDisplayClass: "RectReplacement",
  5509. /**
  5510. * APIProperty: minRatio
  5511. * {Float} The ratio of the overview map resolution to the main map
  5512. * resolution at which to zoom farther out on the overview map.
  5513. */
  5514. minRatio: 8,
  5515. /**
  5516. * APIProperty: maxRatio
  5517. * {Float} The ratio of the overview map resolution to the main map
  5518. * resolution at which to zoom farther in on the overview map.
  5519. */
  5520. maxRatio: 32,
  5521. /**
  5522. * APIProperty: mapOptions
  5523. * {Object} An object containing any non-default properties to be sent to
  5524. * the overview map's map constructor. These should include any
  5525. * non-default options that the main map was constructed with.
  5526. */
  5527. mapOptions: null,
  5528. /**
  5529. * APIProperty: autoPan
  5530. * {Boolean} Always pan the overview map, so the extent marker remains in
  5531. * the center. Default is false. If true, when you drag the extent
  5532. * marker, the overview map will update itself so the marker returns
  5533. * to the center.
  5534. */
  5535. autoPan: false,
  5536. /**
  5537. * Property: handlers
  5538. * {Object}
  5539. */
  5540. handlers: null,
  5541. /**
  5542. * Property: resolutionFactor
  5543. * {Object}
  5544. */
  5545. resolutionFactor: 1,
  5546. /**
  5547. * APIProperty: maximized
  5548. * {Boolean} Start as maximized (visible). Defaults to false.
  5549. */
  5550. maximized: false,
  5551. /**
  5552. * Constructor: OpenLayers.Control.OverviewMap
  5553. * Create a new overview map
  5554. *
  5555. * Parameters:
  5556. * options - {Object} Properties of this object will be set on the overview
  5557. * map object. Note, to set options on the map object contained in this
  5558. * control, set <mapOptions> as one of the options properties.
  5559. */
  5560. initialize: function(options) {
  5561. this.layers = [];
  5562. this.handlers = {};
  5563. OpenLayers.Control.prototype.initialize.apply(this, [options]);
  5564. },
  5565. /**
  5566. * APIMethod: destroy
  5567. * Deconstruct the control
  5568. */
  5569. destroy: function() {
  5570. if (!this.mapDiv) { // we've already been destroyed
  5571. return;
  5572. }
  5573. if (this.handlers.click) {
  5574. this.handlers.click.destroy();
  5575. }
  5576. if (this.handlers.drag) {
  5577. this.handlers.drag.destroy();
  5578. }
  5579. this.ovmap && this.ovmap.viewPortDiv.removeChild(this.extentRectangle);
  5580. this.extentRectangle = null;
  5581. if (this.rectEvents) {
  5582. this.rectEvents.destroy();
  5583. this.rectEvents = null;
  5584. }
  5585. if (this.ovmap) {
  5586. this.ovmap.destroy();
  5587. this.ovmap = null;
  5588. }
  5589. this.element.removeChild(this.mapDiv);
  5590. this.mapDiv = null;
  5591. this.div.removeChild(this.element);
  5592. this.element = null;
  5593. if (this.maximizeDiv) {
  5594. this.div.removeChild(this.maximizeDiv);
  5595. this.maximizeDiv = null;
  5596. }
  5597. if (this.minimizeDiv) {
  5598. this.div.removeChild(this.minimizeDiv);
  5599. this.minimizeDiv = null;
  5600. }
  5601. this.map.events.un({
  5602. buttonclick: this.onButtonClick,
  5603. moveend: this.update,
  5604. changebaselayer: this.baseLayerDraw,
  5605. scope: this
  5606. });
  5607. OpenLayers.Control.prototype.destroy.apply(this, arguments);
  5608. },
  5609. /**
  5610. * Method: draw
  5611. * Render the control in the browser.
  5612. */
  5613. draw: function() {
  5614. OpenLayers.Control.prototype.draw.apply(this, arguments);
  5615. if (this.layers.length === 0) {
  5616. if (this.map.baseLayer) {
  5617. var layer = this.map.baseLayer.clone();
  5618. this.layers = [layer];
  5619. } else {
  5620. this.map.events.register("changebaselayer", this, this.baseLayerDraw);
  5621. return this.div;
  5622. }
  5623. }
  5624. // create overview map DOM elements
  5625. this.element = document.createElement('div');
  5626. this.element.className = this.displayClass + 'Element';
  5627. this.element.style.display = 'none';
  5628. this.mapDiv = document.createElement('div');
  5629. this.mapDiv.style.width = this.size.w + 'px';
  5630. this.mapDiv.style.height = this.size.h + 'px';
  5631. this.mapDiv.style.position = 'relative';
  5632. this.mapDiv.style.overflow = 'hidden';
  5633. this.mapDiv.id = OpenLayers.Util.createUniqueID('overviewMap');
  5634. this.extentRectangle = document.createElement('div');
  5635. this.extentRectangle.style.position = 'absolute';
  5636. this.extentRectangle.style.zIndex = 1000; //HACK
  5637. this.extentRectangle.className = this.displayClass+'ExtentRectangle';
  5638. this.element.appendChild(this.mapDiv);
  5639. this.div.appendChild(this.element);
  5640. // Optionally add min/max buttons if the control will go in the
  5641. // map viewport.
  5642. if(!this.outsideViewport) {
  5643. this.div.className += " " + this.displayClass + 'Container';
  5644. // maximize button div
  5645. var img = OpenLayers.Util.getImageLocation('layer-switcher-maximize.png');
  5646. this.maximizeDiv = OpenLayers.Util.createAlphaImageDiv(
  5647. this.displayClass + 'MaximizeButton',
  5648. null,
  5649. null,
  5650. img,
  5651. 'absolute');
  5652. this.maximizeDiv.style.display = 'none';
  5653. this.maximizeDiv.className = this.displayClass + 'MaximizeButton olButton';
  5654. this.div.appendChild(this.maximizeDiv);
  5655. // minimize button div
  5656. var img = OpenLayers.Util.getImageLocation('layer-switcher-minimize.png');
  5657. this.minimizeDiv = OpenLayers.Util.createAlphaImageDiv(
  5658. 'OpenLayers_Control_minimizeDiv',
  5659. null,
  5660. null,
  5661. img,
  5662. 'absolute');
  5663. this.minimizeDiv.style.display = 'none';
  5664. this.minimizeDiv.className = this.displayClass + 'MinimizeButton olButton';
  5665. this.div.appendChild(this.minimizeDiv);
  5666. this.minimizeControl();
  5667. } else {
  5668. // show the overview map
  5669. this.element.style.display = '';
  5670. }
  5671. if(this.map.getExtent()) {
  5672. this.update();
  5673. }
  5674. this.map.events.on({
  5675. buttonclick: this.onButtonClick,
  5676. moveend: this.update,
  5677. scope: this
  5678. });
  5679. if (this.maximized) {
  5680. this.maximizeControl();
  5681. }
  5682. return this.div;
  5683. },
  5684. /**
  5685. * Method: baseLayerDraw
  5686. * Draw the base layer - called if unable to complete in the initial draw
  5687. */
  5688. baseLayerDraw: function() {
  5689. this.draw();
  5690. this.map.events.unregister("changebaselayer", this, this.baseLayerDraw);
  5691. },
  5692. /**
  5693. * Method: rectDrag
  5694. * Handle extent rectangle drag
  5695. *
  5696. * Parameters:
  5697. * px - {<OpenLayers.Pixel>} The pixel location of the drag.
  5698. */
  5699. rectDrag: function(px) {
  5700. var deltaX = this.handlers.drag.last.x - px.x;
  5701. var deltaY = this.handlers.drag.last.y - px.y;
  5702. if(deltaX != 0 || deltaY != 0) {
  5703. var rectTop = this.rectPxBounds.top;
  5704. var rectLeft = this.rectPxBounds.left;
  5705. var rectHeight = Math.abs(this.rectPxBounds.getHeight());
  5706. var rectWidth = this.rectPxBounds.getWidth();
  5707. // don't allow dragging off of parent element
  5708. var newTop = Math.max(0, (rectTop - deltaY));
  5709. newTop = Math.min(newTop,
  5710. this.ovmap.size.h - this.hComp - rectHeight);
  5711. var newLeft = Math.max(0, (rectLeft - deltaX));
  5712. newLeft = Math.min(newLeft,
  5713. this.ovmap.size.w - this.wComp - rectWidth);
  5714. this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
  5715. newTop + rectHeight,
  5716. newLeft + rectWidth,
  5717. newTop));
  5718. }
  5719. },
  5720. /**
  5721. * Method: mapDivClick
  5722. * Handle browser events
  5723. *
  5724. * Parameters:
  5725. * evt - {<OpenLayers.Event>} evt
  5726. */
  5727. mapDivClick: function(evt) {
  5728. var pxCenter = this.rectPxBounds.getCenterPixel();
  5729. var deltaX = evt.xy.x - pxCenter.x;
  5730. var deltaY = evt.xy.y - pxCenter.y;
  5731. var top = this.rectPxBounds.top;
  5732. var left = this.rectPxBounds.left;
  5733. var height = Math.abs(this.rectPxBounds.getHeight());
  5734. var width = this.rectPxBounds.getWidth();
  5735. var newTop = Math.max(0, (top + deltaY));
  5736. newTop = Math.min(newTop, this.ovmap.size.h - height);
  5737. var newLeft = Math.max(0, (left + deltaX));
  5738. newLeft = Math.min(newLeft, this.ovmap.size.w - width);
  5739. this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
  5740. newTop + height,
  5741. newLeft + width,
  5742. newTop));
  5743. this.updateMapToRect();
  5744. },
  5745. /**
  5746. * Method: onButtonClick
  5747. *
  5748. * Parameters:
  5749. * evt - {Event}
  5750. */
  5751. onButtonClick: function(evt) {
  5752. if (evt.buttonElement === this.minimizeDiv) {
  5753. this.minimizeControl();
  5754. } else if (evt.buttonElement === this.maximizeDiv) {
  5755. this.maximizeControl();
  5756. }
  5757. },
  5758. /**
  5759. * Method: maximizeControl
  5760. * Unhide the control. Called when the control is in the map viewport.
  5761. *
  5762. * Parameters:
  5763. * e - {<OpenLayers.Event>}
  5764. */
  5765. maximizeControl: function(e) {
  5766. this.element.style.display = '';
  5767. this.showToggle(false);
  5768. if (e != null) {
  5769. OpenLayers.Event.stop(e);
  5770. }
  5771. },
  5772. /**
  5773. * Method: minimizeControl
  5774. * Hide all the contents of the control, shrink the size,
  5775. * add the maximize icon
  5776. *
  5777. * Parameters:
  5778. * e - {<OpenLayers.Event>}
  5779. */
  5780. minimizeControl: function(e) {
  5781. this.element.style.display = 'none';
  5782. this.showToggle(true);
  5783. if (e != null) {
  5784. OpenLayers.Event.stop(e);
  5785. }
  5786. },
  5787. /**
  5788. * Method: showToggle
  5789. * Hide/Show the toggle depending on whether the control is minimized
  5790. *
  5791. * Parameters:
  5792. * minimize - {Boolean}
  5793. */
  5794. showToggle: function(minimize) {
  5795. this.maximizeDiv.style.display = minimize ? '' : 'none';
  5796. this.minimizeDiv.style.display = minimize ? 'none' : '';
  5797. },
  5798. /**
  5799. * Method: update
  5800. * Update the overview map after layers move.
  5801. */
  5802. update: function() {
  5803. if(this.ovmap == null) {
  5804. this.createMap();
  5805. }
  5806. if(this.autoPan || !this.isSuitableOverview()) {
  5807. this.updateOverview();
  5808. }
  5809. // update extent rectangle
  5810. this.updateRectToMap();
  5811. },
  5812. /**
  5813. * Method: isSuitableOverview
  5814. * Determines if the overview map is suitable given the extent and
  5815. * resolution of the main map.
  5816. */
  5817. isSuitableOverview: function() {
  5818. var mapExtent = this.map.getExtent();
  5819. var maxExtent = this.map.maxExtent;
  5820. var testExtent = new OpenLayers.Bounds(
  5821. Math.max(mapExtent.left, maxExtent.left),
  5822. Math.max(mapExtent.bottom, maxExtent.bottom),
  5823. Math.min(mapExtent.right, maxExtent.right),
  5824. Math.min(mapExtent.top, maxExtent.top));
  5825. if (this.ovmap.getProjection() != this.map.getProjection()) {
  5826. testExtent = testExtent.transform(
  5827. this.map.getProjectionObject(),
  5828. this.ovmap.getProjectionObject() );
  5829. }
  5830. var resRatio = this.ovmap.getResolution() / this.map.getResolution();
  5831. return ((resRatio > this.minRatio) &&
  5832. (resRatio <= this.maxRatio) &&
  5833. (this.ovmap.getExtent().containsBounds(testExtent)));
  5834. },
  5835. /**
  5836. * Method updateOverview
  5837. * Called by <update> if <isSuitableOverview> returns true
  5838. */
  5839. updateOverview: function() {
  5840. var mapRes = this.map.getResolution();
  5841. var targetRes = this.ovmap.getResolution();
  5842. var resRatio = targetRes / mapRes;
  5843. if(resRatio > this.maxRatio) {
  5844. // zoom in overview map
  5845. targetRes = this.minRatio * mapRes;
  5846. } else if(resRatio <= this.minRatio) {
  5847. // zoom out overview map
  5848. targetRes = this.maxRatio * mapRes;
  5849. }
  5850. var center;
  5851. if (this.ovmap.getProjection() != this.map.getProjection()) {
  5852. center = this.map.center.clone();
  5853. center.transform(this.map.getProjectionObject(),
  5854. this.ovmap.getProjectionObject() );
  5855. } else {
  5856. center = this.map.center;
  5857. }
  5858. this.ovmap.setCenter(center, this.ovmap.getZoomForResolution(
  5859. targetRes * this.resolutionFactor));
  5860. this.updateRectToMap();
  5861. },
  5862. /**
  5863. * Method: createMap
  5864. * Construct the map that this control contains
  5865. */
  5866. createMap: function() {
  5867. // create the overview map
  5868. var options = OpenLayers.Util.extend(
  5869. {controls: [], maxResolution: 'auto',
  5870. fallThrough: false}, this.mapOptions);
  5871. this.ovmap = new OpenLayers.Map(this.mapDiv, options);
  5872. this.ovmap.viewPortDiv.appendChild(this.extentRectangle);
  5873. // prevent ovmap from being destroyed when the page unloads, because
  5874. // the OverviewMap control has to do this (and does it).
  5875. OpenLayers.Event.stopObserving(window, 'unload', this.ovmap.unloadDestroy);
  5876. this.ovmap.addLayers(this.layers);
  5877. this.ovmap.zoomToMaxExtent();
  5878. // check extent rectangle border width
  5879. this.wComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
  5880. 'border-left-width')) +
  5881. parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
  5882. 'border-right-width'));
  5883. this.wComp = (this.wComp) ? this.wComp : 2;
  5884. this.hComp = parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
  5885. 'border-top-width')) +
  5886. parseInt(OpenLayers.Element.getStyle(this.extentRectangle,
  5887. 'border-bottom-width'));
  5888. this.hComp = (this.hComp) ? this.hComp : 2;
  5889. this.handlers.drag = new OpenLayers.Handler.Drag(
  5890. this, {move: this.rectDrag, done: this.updateMapToRect},
  5891. {map: this.ovmap}
  5892. );
  5893. this.handlers.click = new OpenLayers.Handler.Click(
  5894. this, {
  5895. "click": this.mapDivClick
  5896. },{
  5897. "single": true, "double": false,
  5898. "stopSingle": true, "stopDouble": true,
  5899. "pixelTolerance": 1,
  5900. map: this.ovmap
  5901. }
  5902. );
  5903. this.handlers.click.activate();
  5904. this.rectEvents = new OpenLayers.Events(this, this.extentRectangle,
  5905. null, true);
  5906. this.rectEvents.register("mouseover", this, function(e) {
  5907. if(!this.handlers.drag.active && !this.map.dragging) {
  5908. this.handlers.drag.activate();
  5909. }
  5910. });
  5911. this.rectEvents.register("mouseout", this, function(e) {
  5912. if(!this.handlers.drag.dragging) {
  5913. this.handlers.drag.deactivate();
  5914. }
  5915. });
  5916. if (this.ovmap.getProjection() != this.map.getProjection()) {
  5917. var sourceUnits = this.map.getProjectionObject().getUnits() ||
  5918. this.map.units || this.map.baseLayer.units;
  5919. var targetUnits = this.ovmap.getProjectionObject().getUnits() ||
  5920. this.ovmap.units || this.ovmap.baseLayer.units;
  5921. this.resolutionFactor = sourceUnits && targetUnits ?
  5922. OpenLayers.INCHES_PER_UNIT[sourceUnits] /
  5923. OpenLayers.INCHES_PER_UNIT[targetUnits] : 1;
  5924. }
  5925. },
  5926. /**
  5927. * Method: updateRectToMap
  5928. * Updates the extent rectangle position and size to match the map extent
  5929. */
  5930. updateRectToMap: function() {
  5931. // If the projections differ we need to reproject
  5932. var bounds;
  5933. if (this.ovmap.getProjection() != this.map.getProjection()) {
  5934. bounds = this.map.getExtent().transform(
  5935. this.map.getProjectionObject(),
  5936. this.ovmap.getProjectionObject() );
  5937. } else {
  5938. bounds = this.map.getExtent();
  5939. }
  5940. var pxBounds = this.getRectBoundsFromMapBounds(bounds);
  5941. if (pxBounds) {
  5942. this.setRectPxBounds(pxBounds);
  5943. }
  5944. },
  5945. /**
  5946. * Method: updateMapToRect
  5947. * Updates the map extent to match the extent rectangle position and size
  5948. */
  5949. updateMapToRect: function() {
  5950. var lonLatBounds = this.getMapBoundsFromRectBounds(this.rectPxBounds);
  5951. if (this.ovmap.getProjection() != this.map.getProjection()) {
  5952. lonLatBounds = lonLatBounds.transform(
  5953. this.ovmap.getProjectionObject(),
  5954. this.map.getProjectionObject() );
  5955. }
  5956. this.map.panTo(lonLatBounds.getCenterLonLat());
  5957. },
  5958. /**
  5959. * Method: setRectPxBounds
  5960. * Set extent rectangle pixel bounds.
  5961. *
  5962. * Parameters:
  5963. * pxBounds - {<OpenLayers.Bounds>}
  5964. */
  5965. setRectPxBounds: function(pxBounds) {
  5966. var top = Math.max(pxBounds.top, 0);
  5967. var left = Math.max(pxBounds.left, 0);
  5968. var bottom = Math.min(pxBounds.top + Math.abs(pxBounds.getHeight()),
  5969. this.ovmap.size.h - this.hComp);
  5970. var right = Math.min(pxBounds.left + pxBounds.getWidth(),
  5971. this.ovmap.size.w - this.wComp);
  5972. var width = Math.max(right - left, 0);
  5973. var height = Math.max(bottom - top, 0);
  5974. if(width < this.minRectSize || height < this.minRectSize) {
  5975. this.extentRectangle.className = this.displayClass +
  5976. this.minRectDisplayClass;
  5977. var rLeft = left + (width / 2) - (this.minRectSize / 2);
  5978. var rTop = top + (height / 2) - (this.minRectSize / 2);
  5979. this.extentRectangle.style.top = Math.round(rTop) + 'px';
  5980. this.extentRectangle.style.left = Math.round(rLeft) + 'px';
  5981. this.extentRectangle.style.height = this.minRectSize + 'px';
  5982. this.extentRectangle.style.width = this.minRectSize + 'px';
  5983. } else {
  5984. this.extentRectangle.className = this.displayClass +
  5985. 'ExtentRectangle';
  5986. this.extentRectangle.style.top = Math.round(top) + 'px';
  5987. this.extentRectangle.style.left = Math.round(left) + 'px';
  5988. this.extentRectangle.style.height = Math.round(height) + 'px';
  5989. this.extentRectangle.style.width = Math.round(width) + 'px';
  5990. }
  5991. this.rectPxBounds = new OpenLayers.Bounds(
  5992. Math.round(left), Math.round(bottom),
  5993. Math.round(right), Math.round(top)
  5994. );
  5995. },
  5996. /**
  5997. * Method: getRectBoundsFromMapBounds
  5998. * Get the rect bounds from the map bounds.
  5999. *
  6000. * Parameters:
  6001. * lonLatBounds - {<OpenLayers.Bounds>}
  6002. *
  6003. * Returns:
  6004. * {<OpenLayers.Bounds>}A bounds which is the passed-in map lon/lat extent
  6005. * translated into pixel bounds for the overview map
  6006. */
  6007. getRectBoundsFromMapBounds: function(lonLatBounds) {
  6008. var leftBottomPx = this.getOverviewPxFromLonLat({
  6009. lon: lonLatBounds.left,
  6010. lat: lonLatBounds.bottom
  6011. });
  6012. var rightTopPx = this.getOverviewPxFromLonLat({
  6013. lon: lonLatBounds.right,
  6014. lat: lonLatBounds.top
  6015. });
  6016. var bounds = null;
  6017. if (leftBottomPx && rightTopPx) {
  6018. bounds = new OpenLayers.Bounds(leftBottomPx.x, leftBottomPx.y,
  6019. rightTopPx.x, rightTopPx.y);
  6020. }
  6021. return bounds;
  6022. },
  6023. /**
  6024. * Method: getMapBoundsFromRectBounds
  6025. * Get the map bounds from the rect bounds.
  6026. *
  6027. * Parameters:
  6028. * pxBounds - {<OpenLayers.Bounds>}
  6029. *
  6030. * Returns:
  6031. * {<OpenLayers.Bounds>} Bounds which is the passed-in overview rect bounds
  6032. * translated into lon/lat bounds for the overview map
  6033. */
  6034. getMapBoundsFromRectBounds: function(pxBounds) {
  6035. var leftBottomLonLat = this.getLonLatFromOverviewPx({
  6036. x: pxBounds.left,
  6037. y: pxBounds.bottom
  6038. });
  6039. var rightTopLonLat = this.getLonLatFromOverviewPx({
  6040. x: pxBounds.right,
  6041. y: pxBounds.top
  6042. });
  6043. return new OpenLayers.Bounds(leftBottomLonLat.lon, leftBottomLonLat.lat,
  6044. rightTopLonLat.lon, rightTopLonLat.lat);
  6045. },
  6046. /**
  6047. * Method: getLonLatFromOverviewPx
  6048. * Get a map location from a pixel location
  6049. *
  6050. * Parameters:
  6051. * overviewMapPx - {<OpenLayers.Pixel>|Object} OpenLayers.Pixel or
  6052. * an object with a
  6053. * 'x' and 'y' properties.
  6054. *
  6055. * Returns:
  6056. * {Object} Location which is the passed-in overview map
  6057. * OpenLayers.Pixel, translated into lon/lat by the overview
  6058. * map. An object with a 'lon' and 'lat' properties.
  6059. */
  6060. getLonLatFromOverviewPx: function(overviewMapPx) {
  6061. var size = this.ovmap.size;
  6062. var res = this.ovmap.getResolution();
  6063. var center = this.ovmap.getExtent().getCenterLonLat();
  6064. var deltaX = overviewMapPx.x - (size.w / 2);
  6065. var deltaY = overviewMapPx.y - (size.h / 2);
  6066. return {
  6067. lon: center.lon + deltaX * res,
  6068. lat: center.lat - deltaY * res
  6069. };
  6070. },
  6071. /**
  6072. * Method: getOverviewPxFromLonLat
  6073. * Get a pixel location from a map location
  6074. *
  6075. * Parameters:
  6076. * lonlat - {<OpenLayers.LonLat>|Object} OpenLayers.LonLat or an
  6077. * object with a 'lon' and 'lat' properties.
  6078. *
  6079. * Returns:
  6080. * {Object} Location which is the passed-in OpenLayers.LonLat,
  6081. * translated into overview map pixels
  6082. */
  6083. getOverviewPxFromLonLat: function(lonlat) {
  6084. var res = this.ovmap.getResolution();
  6085. var extent = this.ovmap.getExtent();
  6086. if (extent) {
  6087. return {
  6088. x: Math.round(1/res * (lonlat.lon - extent.left)),
  6089. y: Math.round(1/res * (extent.top - lonlat.lat))
  6090. };
  6091. }
  6092. },
  6093. CLASS_NAME: 'OpenLayers.Control.OverviewMap'
  6094. });
  6095. /* ======================================================================
  6096. OpenLayers/Animation.js
  6097. ====================================================================== */
  6098. /**
  6099. * Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  6100. * full list of contributors). Published under the 2-clause BSD license.
  6101. * See license.txt in the OpenLayers distribution or repository for the
  6102. * full text of the license.
  6103. *
  6104. * @requires OpenLayers/SingleFile.js
  6105. */
  6106. /**
  6107. * Namespace: OpenLayers.Animation
  6108. * A collection of utility functions for executing methods that repaint a
  6109. * portion of the browser window. These methods take advantage of the
  6110. * browser's scheduled repaints where requestAnimationFrame is available.
  6111. */
  6112. OpenLayers.Animation = (function(window) {
  6113. /**
  6114. * Property: isNative
  6115. * {Boolean} true if a native requestAnimationFrame function is available
  6116. */
  6117. var isNative = !!(window.requestAnimationFrame ||
  6118. window.webkitRequestAnimationFrame ||
  6119. window.mozRequestAnimationFrame ||
  6120. window.oRequestAnimationFrame ||
  6121. window.msRequestAnimationFrame);
  6122. /**
  6123. * Function: requestFrame
  6124. * Schedule a function to be called at the next available animation frame.
  6125. * Uses the native method where available. Where requestAnimationFrame is
  6126. * not available, setTimeout will be called with a 16ms delay.
  6127. *
  6128. * Parameters:
  6129. * callback - {Function} The function to be called at the next animation frame.
  6130. * element - {DOMElement} Optional element that visually bounds the animation.
  6131. */
  6132. var requestFrame = (function() {
  6133. var request = window.requestAnimationFrame ||
  6134. window.webkitRequestAnimationFrame ||
  6135. window.mozRequestAnimationFrame ||
  6136. window.oRequestAnimationFrame ||
  6137. window.msRequestAnimationFrame ||
  6138. function(callback, element) {
  6139. window.setTimeout(callback, 16);
  6140. };
  6141. // bind to window to avoid illegal invocation of native function
  6142. return function(callback, element) {
  6143. request.apply(window, [callback, element]);
  6144. };
  6145. })();
  6146. // private variables for animation loops
  6147. var counter = 0;
  6148. var loops = {};
  6149. /**
  6150. * Function: start
  6151. * Executes a method with <requestFrame> in series for some
  6152. * duration.
  6153. *
  6154. * Parameters:
  6155. * callback - {Function} The function to be called at the next animation frame.
  6156. * duration - {Number} Optional duration for the loop. If not provided, the
  6157. * animation loop will execute indefinitely.
  6158. * element - {DOMElement} Optional element that visually bounds the animation.
  6159. *
  6160. * Returns:
  6161. * {Number} Identifier for the animation loop. Used to stop animations with
  6162. * <stop>.
  6163. */
  6164. function start(callback, duration, element) {
  6165. duration = duration > 0 ? duration : Number.POSITIVE_INFINITY;
  6166. var id = ++counter;
  6167. var start = +new Date;
  6168. loops[id] = function() {
  6169. if (loops[id] && +new Date - start <= duration) {
  6170. callback();
  6171. if (loops[id]) {
  6172. requestFrame(loops[id], element);
  6173. }
  6174. } else {
  6175. delete loops[id];
  6176. }
  6177. };
  6178. requestFrame(loops[id], element);
  6179. return id;
  6180. }
  6181. /**
  6182. * Function: stop
  6183. * Terminates an animation loop started with <start>.
  6184. *
  6185. * Parameters:
  6186. * id - {Number} Identifier returned from <start>.
  6187. */
  6188. function stop(id) {
  6189. delete loops[id];
  6190. }
  6191. return {
  6192. isNative: isNative,
  6193. requestFrame: requestFrame,
  6194. start: start,
  6195. stop: stop
  6196. };
  6197. })(window);
  6198. /* ======================================================================
  6199. OpenLayers/Tween.js
  6200. ====================================================================== */
  6201. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  6202. * full list of contributors). Published under the 2-clause BSD license.
  6203. * See license.txt in the OpenLayers distribution or repository for the
  6204. * full text of the license. */
  6205. /**
  6206. * @requires OpenLayers/BaseTypes/Class.js
  6207. * @requires OpenLayers/Animation.js
  6208. */
  6209. /**
  6210. * Namespace: OpenLayers.Tween
  6211. */
  6212. OpenLayers.Tween = OpenLayers.Class({
  6213. /**
  6214. * APIProperty: easing
  6215. * {<OpenLayers.Easing>(Function)} Easing equation used for the animation
  6216. * Defaultly set to OpenLayers.Easing.Expo.easeOut
  6217. */
  6218. easing: null,
  6219. /**
  6220. * APIProperty: begin
  6221. * {Object} Values to start the animation with
  6222. */
  6223. begin: null,
  6224. /**
  6225. * APIProperty: finish
  6226. * {Object} Values to finish the animation with
  6227. */
  6228. finish: null,
  6229. /**
  6230. * APIProperty: duration
  6231. * {int} duration of the tween (number of steps)
  6232. */
  6233. duration: null,
  6234. /**
  6235. * APIProperty: callbacks
  6236. * {Object} An object with start, eachStep and done properties whose values
  6237. * are functions to be call during the animation. They are passed the
  6238. * current computed value as argument.
  6239. */
  6240. callbacks: null,
  6241. /**
  6242. * Property: time
  6243. * {int} Step counter
  6244. */
  6245. time: null,
  6246. /**
  6247. * Property: animationId
  6248. * {int} Loop id returned by OpenLayers.Animation.start
  6249. */
  6250. animationId: null,
  6251. /**
  6252. * Property: playing
  6253. * {Boolean} Tells if the easing is currently playing
  6254. */
  6255. playing: false,
  6256. /**
  6257. * Constructor: OpenLayers.Tween
  6258. * Creates a Tween.
  6259. *
  6260. * Parameters:
  6261. * easing - {<OpenLayers.Easing>(Function)} easing function method to use
  6262. */
  6263. initialize: function(easing) {
  6264. this.easing = (easing) ? easing : OpenLayers.Easing.Expo.easeOut;
  6265. },
  6266. /**
  6267. * APIMethod: start
  6268. * Plays the Tween, and calls the callback method on each step
  6269. *
  6270. * Parameters:
  6271. * begin - {Object} values to start the animation with
  6272. * finish - {Object} values to finish the animation with
  6273. * duration - {int} duration of the tween (number of steps)
  6274. * options - {Object} hash of options (for example callbacks (start, eachStep, done))
  6275. */
  6276. start: function(begin, finish, duration, options) {
  6277. this.playing = true;
  6278. this.begin = begin;
  6279. this.finish = finish;
  6280. this.duration = duration;
  6281. this.callbacks = options.callbacks;
  6282. this.time = 0;
  6283. OpenLayers.Animation.stop(this.animationId);
  6284. this.animationId = null;
  6285. if (this.callbacks && this.callbacks.start) {
  6286. this.callbacks.start.call(this, this.begin);
  6287. }
  6288. this.animationId = OpenLayers.Animation.start(
  6289. OpenLayers.Function.bind(this.play, this)
  6290. );
  6291. },
  6292. /**
  6293. * APIMethod: stop
  6294. * Stops the Tween, and calls the done callback
  6295. * Doesn't do anything if animation is already finished
  6296. */
  6297. stop: function() {
  6298. if (!this.playing) {
  6299. return;
  6300. }
  6301. if (this.callbacks && this.callbacks.done) {
  6302. this.callbacks.done.call(this, this.finish);
  6303. }
  6304. OpenLayers.Animation.stop(this.animationId);
  6305. this.animationId = null;
  6306. this.playing = false;
  6307. },
  6308. /**
  6309. * Method: play
  6310. * Calls the appropriate easing method
  6311. */
  6312. play: function() {
  6313. var value = {};
  6314. for (var i in this.begin) {
  6315. var b = this.begin[i];
  6316. var f = this.finish[i];
  6317. if (b == null || f == null || isNaN(b) || isNaN(f)) {
  6318. throw new TypeError('invalid value for Tween');
  6319. }
  6320. var c = f - b;
  6321. value[i] = this.easing.apply(this, [this.time, b, c, this.duration]);
  6322. }
  6323. this.time++;
  6324. if (this.callbacks && this.callbacks.eachStep) {
  6325. this.callbacks.eachStep.call(this, value);
  6326. }
  6327. if (this.time > this.duration) {
  6328. this.stop();
  6329. }
  6330. },
  6331. /**
  6332. * Create empty functions for all easing methods.
  6333. */
  6334. CLASS_NAME: "OpenLayers.Tween"
  6335. });
  6336. /**
  6337. * Namespace: OpenLayers.Easing
  6338. *
  6339. * Credits:
  6340. * Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>
  6341. */
  6342. OpenLayers.Easing = {
  6343. /**
  6344. * Create empty functions for all easing methods.
  6345. */
  6346. CLASS_NAME: "OpenLayers.Easing"
  6347. };
  6348. /**
  6349. * Namespace: OpenLayers.Easing.Linear
  6350. */
  6351. OpenLayers.Easing.Linear = {
  6352. /**
  6353. * Function: easeIn
  6354. *
  6355. * Parameters:
  6356. * t - {Float} time
  6357. * b - {Float} beginning position
  6358. * c - {Float} total change
  6359. * d - {Float} duration of the transition
  6360. *
  6361. * Returns:
  6362. * {Float}
  6363. */
  6364. easeIn: function(t, b, c, d) {
  6365. return c*t/d + b;
  6366. },
  6367. /**
  6368. * Function: easeOut
  6369. *
  6370. * Parameters:
  6371. * t - {Float} time
  6372. * b - {Float} beginning position
  6373. * c - {Float} total change
  6374. * d - {Float} duration of the transition
  6375. *
  6376. * Returns:
  6377. * {Float}
  6378. */
  6379. easeOut: function(t, b, c, d) {
  6380. return c*t/d + b;
  6381. },
  6382. /**
  6383. * Function: easeInOut
  6384. *
  6385. * Parameters:
  6386. * t - {Float} time
  6387. * b - {Float} beginning position
  6388. * c - {Float} total change
  6389. * d - {Float} duration of the transition
  6390. *
  6391. * Returns:
  6392. * {Float}
  6393. */
  6394. easeInOut: function(t, b, c, d) {
  6395. return c*t/d + b;
  6396. },
  6397. CLASS_NAME: "OpenLayers.Easing.Linear"
  6398. };
  6399. /**
  6400. * Namespace: OpenLayers.Easing.Expo
  6401. */
  6402. OpenLayers.Easing.Expo = {
  6403. /**
  6404. * Function: easeIn
  6405. *
  6406. * Parameters:
  6407. * t - {Float} time
  6408. * b - {Float} beginning position
  6409. * c - {Float} total change
  6410. * d - {Float} duration of the transition
  6411. *
  6412. * Returns:
  6413. * {Float}
  6414. */
  6415. easeIn: function(t, b, c, d) {
  6416. return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  6417. },
  6418. /**
  6419. * Function: easeOut
  6420. *
  6421. * Parameters:
  6422. * t - {Float} time
  6423. * b - {Float} beginning position
  6424. * c - {Float} total change
  6425. * d - {Float} duration of the transition
  6426. *
  6427. * Returns:
  6428. * {Float}
  6429. */
  6430. easeOut: function(t, b, c, d) {
  6431. return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  6432. },
  6433. /**
  6434. * Function: easeInOut
  6435. *
  6436. * Parameters:
  6437. * t - {Float} time
  6438. * b - {Float} beginning position
  6439. * c - {Float} total change
  6440. * d - {Float} duration of the transition
  6441. *
  6442. * Returns:
  6443. * {Float}
  6444. */
  6445. easeInOut: function(t, b, c, d) {
  6446. if (t==0) return b;
  6447. if (t==d) return b+c;
  6448. if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
  6449. return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  6450. },
  6451. CLASS_NAME: "OpenLayers.Easing.Expo"
  6452. };
  6453. /**
  6454. * Namespace: OpenLayers.Easing.Quad
  6455. */
  6456. OpenLayers.Easing.Quad = {
  6457. /**
  6458. * Function: easeIn
  6459. *
  6460. * Parameters:
  6461. * t - {Float} time
  6462. * b - {Float} beginning position
  6463. * c - {Float} total change
  6464. * d - {Float} duration of the transition
  6465. *
  6466. * Returns:
  6467. * {Float}
  6468. */
  6469. easeIn: function(t, b, c, d) {
  6470. return c*(t/=d)*t + b;
  6471. },
  6472. /**
  6473. * Function: easeOut
  6474. *
  6475. * Parameters:
  6476. * t - {Float} time
  6477. * b - {Float} beginning position
  6478. * c - {Float} total change
  6479. * d - {Float} duration of the transition
  6480. *
  6481. * Returns:
  6482. * {Float}
  6483. */
  6484. easeOut: function(t, b, c, d) {
  6485. return -c *(t/=d)*(t-2) + b;
  6486. },
  6487. /**
  6488. * Function: easeInOut
  6489. *
  6490. * Parameters:
  6491. * t - {Float} time
  6492. * b - {Float} beginning position
  6493. * c - {Float} total change
  6494. * d - {Float} duration of the transition
  6495. *
  6496. * Returns:
  6497. * {Float}
  6498. */
  6499. easeInOut: function(t, b, c, d) {
  6500. if ((t/=d/2) < 1) return c/2*t*t + b;
  6501. return -c/2 * ((--t)*(t-2) - 1) + b;
  6502. },
  6503. CLASS_NAME: "OpenLayers.Easing.Quad"
  6504. };
  6505. /* ======================================================================
  6506. OpenLayers/Projection.js
  6507. ====================================================================== */
  6508. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  6509. * full list of contributors). Published under the 2-clause BSD license.
  6510. * See license.txt in the OpenLayers distribution or repository for the
  6511. * full text of the license. */
  6512. /**
  6513. * @requires OpenLayers/BaseTypes/Class.js
  6514. * @requires OpenLayers/Util.js
  6515. */
  6516. /**
  6517. * Namespace: OpenLayers.Projection
  6518. * Methods for coordinate transforms between coordinate systems. By default,
  6519. * OpenLayers ships with the ability to transform coordinates between
  6520. * geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)
  6521. * coordinate reference systems. See the <transform> method for details
  6522. * on usage.
  6523. *
  6524. * Additional transforms may be added by using the <proj4js at http://proj4js.org/>
  6525. * library. If the proj4js library is included, the <transform> method
  6526. * will work between any two coordinate reference systems with proj4js
  6527. * definitions.
  6528. *
  6529. * If the proj4js library is not included, or if you wish to allow transforms
  6530. * between arbitrary coordinate reference systems, use the <addTransform>
  6531. * method to register a custom transform method.
  6532. */
  6533. OpenLayers.Projection = OpenLayers.Class({
  6534. /**
  6535. * Property: proj
  6536. * {Object} Proj4js.Proj instance.
  6537. */
  6538. proj: null,
  6539. /**
  6540. * Property: projCode
  6541. * {String}
  6542. */
  6543. projCode: null,
  6544. /**
  6545. * Property: titleRegEx
  6546. * {RegExp} regular expression to strip the title from a proj4js definition
  6547. */
  6548. titleRegEx: /\+title=[^\+]*/,
  6549. /**
  6550. * Constructor: OpenLayers.Projection
  6551. * This class offers several methods for interacting with a wrapped
  6552. * pro4js projection object.
  6553. *
  6554. * Parameters:
  6555. * projCode - {String} A string identifying the Well Known Identifier for
  6556. * the projection.
  6557. * options - {Object} An optional object to set additional properties
  6558. * on the projection.
  6559. *
  6560. * Returns:
  6561. * {<OpenLayers.Projection>} A projection object.
  6562. */
  6563. initialize: function(projCode, options) {
  6564. OpenLayers.Util.extend(this, options);
  6565. this.projCode = projCode;
  6566. if (window.Proj4js) {
  6567. this.proj = new Proj4js.Proj(projCode);
  6568. }
  6569. },
  6570. /**
  6571. * APIMethod: getCode
  6572. * Get the string SRS code.
  6573. *
  6574. * Returns:
  6575. * {String} The SRS code.
  6576. */
  6577. getCode: function() {
  6578. return this.proj ? this.proj.srsCode : this.projCode;
  6579. },
  6580. /**
  6581. * APIMethod: getUnits
  6582. * Get the units string for the projection -- returns null if
  6583. * proj4js is not available.
  6584. *
  6585. * Returns:
  6586. * {String} The units abbreviation.
  6587. */
  6588. getUnits: function() {
  6589. return this.proj ? this.proj.units : null;
  6590. },
  6591. /**
  6592. * Method: toString
  6593. * Convert projection to string (getCode wrapper).
  6594. *
  6595. * Returns:
  6596. * {String} The projection code.
  6597. */
  6598. toString: function() {
  6599. return this.getCode();
  6600. },
  6601. /**
  6602. * Method: equals
  6603. * Test equality of two projection instances. Determines equality based
  6604. * soley on the projection code.
  6605. *
  6606. * Returns:
  6607. * {Boolean} The two projections are equivalent.
  6608. */
  6609. equals: function(projection) {
  6610. var p = projection, equals = false;
  6611. if (p) {
  6612. if (!(p instanceof OpenLayers.Projection)) {
  6613. p = new OpenLayers.Projection(p);
  6614. }
  6615. if (window.Proj4js && this.proj.defData && p.proj.defData) {
  6616. equals = this.proj.defData.replace(this.titleRegEx, "") ==
  6617. p.proj.defData.replace(this.titleRegEx, "");
  6618. } else if (p.getCode) {
  6619. var source = this.getCode(), target = p.getCode();
  6620. equals = source == target ||
  6621. !!OpenLayers.Projection.transforms[source] &&
  6622. OpenLayers.Projection.transforms[source][target] ===
  6623. OpenLayers.Projection.nullTransform;
  6624. }
  6625. }
  6626. return equals;
  6627. },
  6628. /* Method: destroy
  6629. * Destroy projection object.
  6630. */
  6631. destroy: function() {
  6632. delete this.proj;
  6633. delete this.projCode;
  6634. },
  6635. CLASS_NAME: "OpenLayers.Projection"
  6636. });
  6637. /**
  6638. * Property: transforms
  6639. * {Object} Transforms is an object, with from properties, each of which may
  6640. * have a to property. This allows you to define projections without
  6641. * requiring support for proj4js to be included.
  6642. *
  6643. * This object has keys which correspond to a 'source' projection object. The
  6644. * keys should be strings, corresponding to the projection.getCode() value.
  6645. * Each source projection object should have a set of destination projection
  6646. * keys included in the object.
  6647. *
  6648. * Each value in the destination object should be a transformation function,
  6649. * where the function is expected to be passed an object with a .x and a .y
  6650. * property. The function should return the object, with the .x and .y
  6651. * transformed according to the transformation function.
  6652. *
  6653. * Note - Properties on this object should not be set directly. To add a
  6654. * transform method to this object, use the <addTransform> method. For an
  6655. * example of usage, see the OpenLayers.Layer.SphericalMercator file.
  6656. */
  6657. OpenLayers.Projection.transforms = {};
  6658. /**
  6659. * APIProperty: defaults
  6660. * {Object} Defaults for the SRS codes known to OpenLayers (currently
  6661. * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,
  6662. * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,
  6663. * maxExtent (the validity extent for the SRS) and yx (true if this SRS is
  6664. * known to have a reverse axis order).
  6665. */
  6666. OpenLayers.Projection.defaults = {
  6667. "EPSG:4326": {
  6668. units: "degrees",
  6669. maxExtent: [-180, -90, 180, 90],
  6670. yx: true
  6671. },
  6672. "CRS:84": {
  6673. units: "degrees",
  6674. maxExtent: [-180, -90, 180, 90]
  6675. },
  6676. "EPSG:900913": {
  6677. units: "m",
  6678. maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
  6679. }
  6680. };
  6681. /**
  6682. * APIMethod: addTransform
  6683. * Set a custom transform method between two projections. Use this method in
  6684. * cases where the proj4js lib is not available or where custom projections
  6685. * need to be handled.
  6686. *
  6687. * Parameters:
  6688. * from - {String} The code for the source projection
  6689. * to - {String} the code for the destination projection
  6690. * method - {Function} A function that takes a point as an argument and
  6691. * transforms that point from the source to the destination projection
  6692. * in place. The original point should be modified.
  6693. */
  6694. OpenLayers.Projection.addTransform = function(from, to, method) {
  6695. if (method === OpenLayers.Projection.nullTransform) {
  6696. var defaults = OpenLayers.Projection.defaults[from];
  6697. if (defaults && !OpenLayers.Projection.defaults[to]) {
  6698. OpenLayers.Projection.defaults[to] = defaults;
  6699. }
  6700. }
  6701. if(!OpenLayers.Projection.transforms[from]) {
  6702. OpenLayers.Projection.transforms[from] = {};
  6703. }
  6704. OpenLayers.Projection.transforms[from][to] = method;
  6705. };
  6706. /**
  6707. * APIMethod: transform
  6708. * Transform a point coordinate from one projection to another. Note that
  6709. * the input point is transformed in place.
  6710. *
  6711. * Parameters:
  6712. * point - {<OpenLayers.Geometry.Point> | Object} An object with x and y
  6713. * properties representing coordinates in those dimensions.
  6714. * source - {OpenLayers.Projection} Source map coordinate system
  6715. * dest - {OpenLayers.Projection} Destination map coordinate system
  6716. *
  6717. * Returns:
  6718. * point - {object} A transformed coordinate. The original point is modified.
  6719. */
  6720. OpenLayers.Projection.transform = function(point, source, dest) {
  6721. if (source && dest) {
  6722. if (!(source instanceof OpenLayers.Projection)) {
  6723. source = new OpenLayers.Projection(source);
  6724. }
  6725. if (!(dest instanceof OpenLayers.Projection)) {
  6726. dest = new OpenLayers.Projection(dest);
  6727. }
  6728. if (source.proj && dest.proj) {
  6729. point = Proj4js.transform(source.proj, dest.proj, point);
  6730. } else {
  6731. var sourceCode = source.getCode();
  6732. var destCode = dest.getCode();
  6733. var transforms = OpenLayers.Projection.transforms;
  6734. if (transforms[sourceCode] && transforms[sourceCode][destCode]) {
  6735. transforms[sourceCode][destCode](point);
  6736. }
  6737. }
  6738. }
  6739. return point;
  6740. };
  6741. /**
  6742. * APIFunction: nullTransform
  6743. * A null transformation - useful for defining projection aliases when
  6744. * proj4js is not available:
  6745. *
  6746. * (code)
  6747. * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913",
  6748. * OpenLayers.Projection.nullTransform);
  6749. * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857",
  6750. * OpenLayers.Projection.nullTransform);
  6751. * (end)
  6752. */
  6753. OpenLayers.Projection.nullTransform = function(point) {
  6754. return point;
  6755. };
  6756. /**
  6757. * Note: Transforms for web mercator <-> geographic
  6758. * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
  6759. * OpenLayers originally started referring to EPSG:900913 as web mercator.
  6760. * The EPSG has declared EPSG:3857 to be web mercator.
  6761. * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
  6762. * equivalent. See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084.
  6763. * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and
  6764. * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis
  6765. * order for EPSG:4326.
  6766. */
  6767. (function() {
  6768. var pole = 20037508.34;
  6769. function inverseMercator(xy) {
  6770. xy.x = 180 * xy.x / pole;
  6771. xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);
  6772. return xy;
  6773. }
  6774. function forwardMercator(xy) {
  6775. xy.x = xy.x * pole / 180;
  6776. xy.y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;
  6777. return xy;
  6778. }
  6779. function map(base, codes) {
  6780. var add = OpenLayers.Projection.addTransform;
  6781. var same = OpenLayers.Projection.nullTransform;
  6782. var i, len, code, other, j;
  6783. for (i=0, len=codes.length; i<len; ++i) {
  6784. code = codes[i];
  6785. add(base, code, forwardMercator);
  6786. add(code, base, inverseMercator);
  6787. for (j=i+1; j<len; ++j) {
  6788. other = codes[j];
  6789. add(code, other, same);
  6790. add(other, code, same);
  6791. }
  6792. }
  6793. }
  6794. // list of equivalent codes for web mercator
  6795. var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"],
  6796. geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"],
  6797. i;
  6798. for (i=mercator.length-1; i>=0; --i) {
  6799. map(mercator[i], geographic);
  6800. }
  6801. for (i=geographic.length-1; i>=0; --i) {
  6802. map(geographic[i], mercator);
  6803. }
  6804. })();
  6805. /* ======================================================================
  6806. OpenLayers/Map.js
  6807. ====================================================================== */
  6808. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  6809. * full list of contributors). Published under the 2-clause BSD license.
  6810. * See license.txt in the OpenLayers distribution or repository for the
  6811. * full text of the license. */
  6812. /**
  6813. * @requires OpenLayers/BaseTypes/Class.js
  6814. * @requires OpenLayers/Util.js
  6815. * @requires OpenLayers/Events.js
  6816. * @requires OpenLayers/Tween.js
  6817. * @requires OpenLayers/Projection.js
  6818. */
  6819. /**
  6820. * Class: OpenLayers.Map
  6821. * Instances of OpenLayers.Map are interactive maps embedded in a web page.
  6822. * Create a new map with the <OpenLayers.Map> constructor.
  6823. *
  6824. * On their own maps do not provide much functionality. To extend a map
  6825. * it's necessary to add controls (<OpenLayers.Control>) and
  6826. * layers (<OpenLayers.Layer>) to the map.
  6827. */
  6828. OpenLayers.Map = OpenLayers.Class({
  6829. /**
  6830. * Constant: Z_INDEX_BASE
  6831. * {Object} Base z-indexes for different classes of thing
  6832. */
  6833. Z_INDEX_BASE: {
  6834. BaseLayer: 100,
  6835. Overlay: 325,
  6836. Feature: 725,
  6837. Popup: 750,
  6838. Control: 1000
  6839. },
  6840. /**
  6841. * APIProperty: events
  6842. * {<OpenLayers.Events>}
  6843. *
  6844. * Register a listener for a particular event with the following syntax:
  6845. * (code)
  6846. * map.events.register(type, obj, listener);
  6847. * (end)
  6848. *
  6849. * Listeners will be called with a reference to an event object. The
  6850. * properties of this event depends on exactly what happened.
  6851. *
  6852. * All event objects have at least the following properties:
  6853. * object - {Object} A reference to map.events.object.
  6854. * element - {DOMElement} A reference to map.events.element.
  6855. *
  6856. * Browser events have the following additional properties:
  6857. * xy - {<OpenLayers.Pixel>} The pixel location of the event (relative
  6858. * to the the map viewport).
  6859. *
  6860. * Supported map event types:
  6861. * preaddlayer - triggered before a layer has been added. The event
  6862. * object will include a *layer* property that references the layer
  6863. * to be added. When a listener returns "false" the adding will be
  6864. * aborted.
  6865. * addlayer - triggered after a layer has been added. The event object
  6866. * will include a *layer* property that references the added layer.
  6867. * preremovelayer - triggered before a layer has been removed. The event
  6868. * object will include a *layer* property that references the layer
  6869. * to be removed. When a listener returns "false" the removal will be
  6870. * aborted.
  6871. * removelayer - triggered after a layer has been removed. The event
  6872. * object will include a *layer* property that references the removed
  6873. * layer.
  6874. * changelayer - triggered after a layer name change, order change,
  6875. * opacity change, params change, visibility change (due to resolution
  6876. * thresholds) or attribution change (due to extent change). Listeners
  6877. * will receive an event object with *layer* and *property* properties.
  6878. * The *layer* property will be a reference to the changed layer. The
  6879. * *property* property will be a key to the changed property (name,
  6880. * order, opacity, params, visibility or attribution).
  6881. * movestart - triggered after the start of a drag, pan, or zoom
  6882. * move - triggered after each drag, pan, or zoom
  6883. * moveend - triggered after a drag, pan, or zoom completes
  6884. * zoomend - triggered after a zoom completes
  6885. * mouseover - triggered after mouseover the map
  6886. * mouseout - triggered after mouseout the map
  6887. * mousemove - triggered after mousemove the map
  6888. * changebaselayer - triggered after the base layer changes
  6889. */
  6890. /**
  6891. * Property: id
  6892. * {String} Unique identifier for the map
  6893. */
  6894. id: null,
  6895. /**
  6896. * Property: fractionalZoom
  6897. * {Boolean} For a base layer that supports it, allow the map resolution
  6898. * to be set to a value between one of the values in the resolutions
  6899. * array. Default is false.
  6900. *
  6901. * When fractionalZoom is set to true, it is possible to zoom to
  6902. * an arbitrary extent. This requires a base layer from a source
  6903. * that supports requests for arbitrary extents (i.e. not cached
  6904. * tiles on a regular lattice). This means that fractionalZoom
  6905. * will not work with commercial layers (Google, Yahoo, VE), layers
  6906. * using TileCache, or any other pre-cached data sources.
  6907. *
  6908. * If you are using fractionalZoom, then you should also use
  6909. * <getResolutionForZoom> instead of layer.resolutions[zoom] as the
  6910. * former works for non-integer zoom levels.
  6911. */
  6912. fractionalZoom: false,
  6913. /**
  6914. * APIProperty: events
  6915. * {<OpenLayers.Events>} An events object that handles all
  6916. * events on the map
  6917. */
  6918. events: null,
  6919. /**
  6920. * APIProperty: allOverlays
  6921. * {Boolean} Allow the map to function with "overlays" only. Defaults to
  6922. * false. If true, the lowest layer in the draw order will act as
  6923. * the base layer. In addition, if set to true, all layers will
  6924. * have isBaseLayer set to false when they are added to the map.
  6925. *
  6926. * Note:
  6927. * If you set map.allOverlays to true, then you *cannot* use
  6928. * map.setBaseLayer or layer.setIsBaseLayer. With allOverlays true,
  6929. * the lowest layer in the draw layer is the base layer. So, to change
  6930. * the base layer, use <setLayerIndex> or <raiseLayer> to set the layer
  6931. * index to 0.
  6932. */
  6933. allOverlays: false,
  6934. /**
  6935. * APIProperty: div
  6936. * {DOMElement|String} The element that contains the map (or an id for
  6937. * that element). If the <OpenLayers.Map> constructor is called
  6938. * with two arguments, this should be provided as the first argument.
  6939. * Alternatively, the map constructor can be called with the options
  6940. * object as the only argument. In this case (one argument), a
  6941. * div property may or may not be provided. If the div property
  6942. * is not provided, the map can be rendered to a container later
  6943. * using the <render> method.
  6944. *
  6945. * Note:
  6946. * If you are calling <render> after map construction, do not use
  6947. * <maxResolution> auto. Instead, divide your <maxExtent> by your
  6948. * maximum expected dimension.
  6949. */
  6950. div: null,
  6951. /**
  6952. * Property: dragging
  6953. * {Boolean} The map is currently being dragged.
  6954. */
  6955. dragging: false,
  6956. /**
  6957. * Property: size
  6958. * {<OpenLayers.Size>} Size of the main div (this.div)
  6959. */
  6960. size: null,
  6961. /**
  6962. * Property: viewPortDiv
  6963. * {HTMLDivElement} The element that represents the map viewport
  6964. */
  6965. viewPortDiv: null,
  6966. /**
  6967. * Property: layerContainerOrigin
  6968. * {<OpenLayers.LonLat>} The lonlat at which the later container was
  6969. * re-initialized (on-zoom)
  6970. */
  6971. layerContainerOrigin: null,
  6972. /**
  6973. * Property: layerContainerDiv
  6974. * {HTMLDivElement} The element that contains the layers.
  6975. */
  6976. layerContainerDiv: null,
  6977. /**
  6978. * APIProperty: layers
  6979. * {Array(<OpenLayers.Layer>)} Ordered list of layers in the map
  6980. */
  6981. layers: null,
  6982. /**
  6983. * APIProperty: controls
  6984. * {Array(<OpenLayers.Control>)} List of controls associated with the map.
  6985. *
  6986. * If not provided in the map options at construction, the map will
  6987. * by default be given the following controls if present in the build:
  6988. * - <OpenLayers.Control.Navigation> or <OpenLayers.Control.TouchNavigation>
  6989. * - <OpenLayers.Control.Zoom> or <OpenLayers.Control.PanZoom>
  6990. * - <OpenLayers.Control.ArgParser>
  6991. * - <OpenLayers.Control.Attribution>
  6992. */
  6993. controls: null,
  6994. /**
  6995. * Property: popups
  6996. * {Array(<OpenLayers.Popup>)} List of popups associated with the map
  6997. */
  6998. popups: null,
  6999. /**
  7000. * APIProperty: baseLayer
  7001. * {<OpenLayers.Layer>} The currently selected base layer. This determines
  7002. * min/max zoom level, projection, etc.
  7003. */
  7004. baseLayer: null,
  7005. /**
  7006. * Property: center
  7007. * {<OpenLayers.LonLat>} The current center of the map
  7008. */
  7009. center: null,
  7010. /**
  7011. * Property: resolution
  7012. * {Float} The resolution of the map.
  7013. */
  7014. resolution: null,
  7015. /**
  7016. * Property: zoom
  7017. * {Integer} The current zoom level of the map
  7018. */
  7019. zoom: 0,
  7020. /**
  7021. * Property: panRatio
  7022. * {Float} The ratio of the current extent within
  7023. * which panning will tween.
  7024. */
  7025. panRatio: 1.5,
  7026. /**
  7027. * APIProperty: options
  7028. * {Object} The options object passed to the class constructor. Read-only.
  7029. */
  7030. options: null,
  7031. // Options
  7032. /**
  7033. * APIProperty: tileSize
  7034. * {<OpenLayers.Size>} Set in the map options to override the default tile
  7035. * size for this map.
  7036. */
  7037. tileSize: null,
  7038. /**
  7039. * APIProperty: projection
  7040. * {String} Set in the map options to specify the default projection
  7041. * for layers added to this map. When using a projection other than EPSG:4326
  7042. * (CRS:84, Geographic) or EPSG:3857 (EPSG:900913, Web Mercator),
  7043. * also set maxExtent, maxResolution or resolutions. Default is "EPSG:4326".
  7044. * Note that the projection of the map is usually determined
  7045. * by that of the current baseLayer (see <baseLayer> and <getProjectionObject>).
  7046. */
  7047. projection: "EPSG:4326",
  7048. /**
  7049. * APIProperty: units
  7050. * {String} The map units. Possible values are 'degrees' (or 'dd'), 'm',
  7051. * 'ft', 'km', 'mi', 'inches'. Normally taken from the projection.
  7052. * Only required if both map and layers do not define a projection,
  7053. * or if they define a projection which does not define units
  7054. */
  7055. units: null,
  7056. /**
  7057. * APIProperty: resolutions
  7058. * {Array(Float)} A list of map resolutions (map units per pixel) in
  7059. * descending order. If this is not set in the layer constructor, it
  7060. * will be set based on other resolution related properties
  7061. * (maxExtent, maxResolution, maxScale, etc.).
  7062. */
  7063. resolutions: null,
  7064. /**
  7065. * APIProperty: maxResolution
  7066. * {Float} Required if you are not displaying the whole world on a tile
  7067. * with the size specified in <tileSize>.
  7068. */
  7069. maxResolution: null,
  7070. /**
  7071. * APIProperty: minResolution
  7072. * {Float}
  7073. */
  7074. minResolution: null,
  7075. /**
  7076. * APIProperty: maxScale
  7077. * {Float}
  7078. */
  7079. maxScale: null,
  7080. /**
  7081. * APIProperty: minScale
  7082. * {Float}
  7083. */
  7084. minScale: null,
  7085. /**
  7086. * APIProperty: maxExtent
  7087. * {<OpenLayers.Bounds>|Array} If provided as an array, the array
  7088. * should consist of four values (left, bottom, right, top).
  7089. * The maximum extent for the map. Defaults to the
  7090. * whole world in decimal degrees (-180, -90, 180, 90). Specify a
  7091. * different extent in the map options if you are not using a geographic
  7092. * projection and displaying the whole world. To restrict user panning
  7093. * and zooming of the map, use <restrictedExtent> instead. The value
  7094. * for <maxExtent> will change calculations for tile URLs.
  7095. */
  7096. maxExtent: null,
  7097. /**
  7098. * APIProperty: minExtent
  7099. * {<OpenLayers.Bounds>|Array} If provided as an array, the array
  7100. * should consist of four values (left, bottom, right, top).
  7101. * The minimum extent for the map. Defaults to null.
  7102. */
  7103. minExtent: null,
  7104. /**
  7105. * APIProperty: restrictedExtent
  7106. * {<OpenLayers.Bounds>|Array} If provided as an array, the array
  7107. * should consist of four values (left, bottom, right, top).
  7108. * Limit map navigation to this extent where possible.
  7109. * If a non-null restrictedExtent is set, panning will be restricted
  7110. * to the given bounds. In addition, zooming to a resolution that
  7111. * displays more than the restricted extent will center the map
  7112. * on the restricted extent. If you wish to limit the zoom level
  7113. * or resolution, use maxResolution.
  7114. */
  7115. restrictedExtent: null,
  7116. /**
  7117. * APIProperty: numZoomLevels
  7118. * {Integer} Number of zoom levels for the map. Defaults to 16. Set a
  7119. * different value in the map options if needed.
  7120. */
  7121. numZoomLevels: 16,
  7122. /**
  7123. * APIProperty: theme
  7124. * {String} Relative path to a CSS file from which to load theme styles.
  7125. * Specify null in the map options (e.g. {theme: null}) if you
  7126. * want to get cascading style declarations - by putting links to
  7127. * stylesheets or style declarations directly in your page.
  7128. */
  7129. theme: null,
  7130. /**
  7131. * APIProperty: displayProjection
  7132. * {<OpenLayers.Projection>} Requires proj4js support for projections other
  7133. * than EPSG:4326 or EPSG:900913/EPSG:3857. Projection used by
  7134. * several controls to display data to user. If this property is set,
  7135. * it will be set on any control which has a null displayProjection
  7136. * property at the time the control is added to the map.
  7137. */
  7138. displayProjection: null,
  7139. /**
  7140. * APIProperty: fallThrough
  7141. * {Boolean} Should OpenLayers allow events on the map to fall through to
  7142. * other elements on the page, or should it swallow them? (#457)
  7143. * Default is to fall through.
  7144. */
  7145. fallThrough: true,
  7146. /**
  7147. * Property: panTween
  7148. * {<OpenLayers.Tween>} Animated panning tween object, see panTo()
  7149. */
  7150. panTween: null,
  7151. /**
  7152. * APIProperty: eventListeners
  7153. * {Object} If set as an option at construction, the eventListeners
  7154. * object will be registered with <OpenLayers.Events.on>. Object
  7155. * structure must be a listeners object as shown in the example for
  7156. * the events.on method.
  7157. */
  7158. eventListeners: null,
  7159. /**
  7160. * APIProperty: panMethod
  7161. * {Function} The Easing function to be used for tweening. Default is
  7162. * OpenLayers.Easing.Expo.easeOut. Setting this to 'null' turns off
  7163. * animated panning.
  7164. */
  7165. panMethod: OpenLayers.Easing.Expo.easeOut,
  7166. /**
  7167. * Property: panDuration
  7168. * {Integer} The number of steps to be passed to the
  7169. * OpenLayers.Tween.start() method when the map is
  7170. * panned.
  7171. * Default is 50.
  7172. */
  7173. panDuration: 50,
  7174. /**
  7175. * Property: paddingForPopups
  7176. * {<OpenLayers.Bounds>} Outside margin of the popup. Used to prevent
  7177. * the popup from getting too close to the map border.
  7178. */
  7179. paddingForPopups : null,
  7180. /**
  7181. * Property: minPx
  7182. * {Object} An object with a 'x' and 'y' values that is the lower
  7183. * left of maxExtent in viewport pixel space.
  7184. * Used to verify in moveByPx that the new location we're moving to
  7185. * is valid. It is also used in the getLonLatFromViewPortPx function
  7186. * of Layer.
  7187. */
  7188. minPx: null,
  7189. /**
  7190. * Property: maxPx
  7191. * {Object} An object with a 'x' and 'y' values that is the top
  7192. * right of maxExtent in viewport pixel space.
  7193. * Used to verify in moveByPx that the new location we're moving to
  7194. * is valid.
  7195. */
  7196. maxPx: null,
  7197. /**
  7198. * Constructor: OpenLayers.Map
  7199. * Constructor for a new OpenLayers.Map instance. There are two possible
  7200. * ways to call the map constructor. See the examples below.
  7201. *
  7202. * Parameters:
  7203. * div - {DOMElement|String} The element or id of an element in your page
  7204. * that will contain the map. May be omitted if the <div> option is
  7205. * provided or if you intend to call the <render> method later.
  7206. * options - {Object} Optional object with properties to tag onto the map.
  7207. *
  7208. * Valid options (in addition to the listed API properties):
  7209. * center - {<OpenLayers.LonLat>|Array} The default initial center of the map.
  7210. * If provided as array, the first value is the x coordinate,
  7211. * and the 2nd value is the y coordinate.
  7212. * Only specify if <layers> is provided.
  7213. * Note that if an ArgParser/Permalink control is present,
  7214. * and the querystring contains coordinates, center will be set
  7215. * by that, and this option will be ignored.
  7216. * zoom - {Number} The initial zoom level for the map. Only specify if
  7217. * <layers> is provided.
  7218. * Note that if an ArgParser/Permalink control is present,
  7219. * and the querystring contains a zoom level, zoom will be set
  7220. * by that, and this option will be ignored.
  7221. * extent - {<OpenLayers.Bounds>|Array} The initial extent of the map.
  7222. * If provided as an array, the array should consist of
  7223. * four values (left, bottom, right, top).
  7224. * Only specify if <center> and <zoom> are not provided.
  7225. *
  7226. * Examples:
  7227. * (code)
  7228. * // create a map with default options in an element with the id "map1"
  7229. * var map = new OpenLayers.Map("map1");
  7230. *
  7231. * // create a map with non-default options in an element with id "map2"
  7232. * var options = {
  7233. * projection: "EPSG:3857",
  7234. * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
  7235. * center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)
  7236. * };
  7237. * var map = new OpenLayers.Map("map2", options);
  7238. *
  7239. * // map with non-default options - same as above but with a single argument,
  7240. * // a restricted extent, and using arrays for bounds and center
  7241. * var map = new OpenLayers.Map({
  7242. * div: "map_id",
  7243. * projection: "EPSG:3857",
  7244. * maxExtent: [-18924313.432222, -15538711.094146, 18924313.432222, 15538711.094146],
  7245. * restrictedExtent: [-13358338.893333, -9608371.5085962, 13358338.893333, 9608371.5085962],
  7246. * center: [-12356463.476333, 5621521.4854095]
  7247. * });
  7248. *
  7249. * // create a map without a reference to a container - call render later
  7250. * var map = new OpenLayers.Map({
  7251. * projection: "EPSG:3857",
  7252. * maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000)
  7253. * });
  7254. * (end)
  7255. */
  7256. initialize: function (div, options) {
  7257. // If only one argument is provided, check if it is an object.
  7258. if(arguments.length === 1 && typeof div === "object") {
  7259. options = div;
  7260. div = options && options.div;
  7261. }
  7262. // Simple-type defaults are set in class definition.
  7263. // Now set complex-type defaults
  7264. this.tileSize = new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,
  7265. OpenLayers.Map.TILE_HEIGHT);
  7266. this.paddingForPopups = new OpenLayers.Bounds(15, 15, 15, 15);
  7267. this.theme = OpenLayers._getScriptLocation() +
  7268. 'theme/default/style.css';
  7269. // backup original options
  7270. this.options = OpenLayers.Util.extend({}, options);
  7271. // now override default options
  7272. OpenLayers.Util.extend(this, options);
  7273. var projCode = this.projection instanceof OpenLayers.Projection ?
  7274. this.projection.projCode : this.projection;
  7275. OpenLayers.Util.applyDefaults(this, OpenLayers.Projection.defaults[projCode]);
  7276. // allow extents and center to be arrays
  7277. if (this.maxExtent && !(this.maxExtent instanceof OpenLayers.Bounds)) {
  7278. this.maxExtent = new OpenLayers.Bounds(this.maxExtent);
  7279. }
  7280. if (this.minExtent && !(this.minExtent instanceof OpenLayers.Bounds)) {
  7281. this.minExtent = new OpenLayers.Bounds(this.minExtent);
  7282. }
  7283. if (this.restrictedExtent && !(this.restrictedExtent instanceof OpenLayers.Bounds)) {
  7284. this.restrictedExtent = new OpenLayers.Bounds(this.restrictedExtent);
  7285. }
  7286. if (this.center && !(this.center instanceof OpenLayers.LonLat)) {
  7287. this.center = new OpenLayers.LonLat(this.center);
  7288. }
  7289. // initialize layers array
  7290. this.layers = [];
  7291. this.id = OpenLayers.Util.createUniqueID("OpenLayers.Map_");
  7292. this.div = OpenLayers.Util.getElement(div);
  7293. if(!this.div) {
  7294. this.div = document.createElement("div");
  7295. this.div.style.height = "1px";
  7296. this.div.style.width = "1px";
  7297. }
  7298. OpenLayers.Element.addClass(this.div, 'olMap');
  7299. // the viewPortDiv is the outermost div we modify
  7300. var id = this.id + "_OpenLayers_ViewPort";
  7301. this.viewPortDiv = OpenLayers.Util.createDiv(id, null, null, null,
  7302. "relative", null,
  7303. "hidden");
  7304. this.viewPortDiv.style.width = "100%";
  7305. this.viewPortDiv.style.height = "100%";
  7306. this.viewPortDiv.className = "olMapViewport";
  7307. this.div.appendChild(this.viewPortDiv);
  7308. this.events = new OpenLayers.Events(
  7309. this, this.viewPortDiv, null, this.fallThrough,
  7310. {includeXY: true}
  7311. );
  7312. // the layerContainerDiv is the one that holds all the layers
  7313. id = this.id + "_OpenLayers_Container";
  7314. this.layerContainerDiv = OpenLayers.Util.createDiv(id);
  7315. this.layerContainerDiv.style.width = '100px';
  7316. this.layerContainerDiv.style.height = '100px';
  7317. this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
  7318. this.viewPortDiv.appendChild(this.layerContainerDiv);
  7319. this.updateSize();
  7320. if(this.eventListeners instanceof Object) {
  7321. this.events.on(this.eventListeners);
  7322. }
  7323. // Because Mozilla does not support the "resize" event for elements
  7324. // other than "window", we need to put a hack here.
  7325. if (parseFloat(navigator.appVersion.split("MSIE")[1]) < 9) {
  7326. // If IE < 9, register the resize on the div
  7327. this.events.register("resize", this, this.updateSize);
  7328. } else {
  7329. // Else updateSize on catching the window's resize
  7330. // Note that this is ok, as updateSize() does nothing if the
  7331. // map's size has not actually changed.
  7332. this.updateSizeDestroy = OpenLayers.Function.bind(this.updateSize,
  7333. this);
  7334. OpenLayers.Event.observe(window, 'resize',
  7335. this.updateSizeDestroy);
  7336. }
  7337. // only append link stylesheet if the theme property is set
  7338. if(this.theme) {
  7339. // check existing links for equivalent url
  7340. var addNode = true;
  7341. var nodes = document.getElementsByTagName('link');
  7342. for(var i=0, len=nodes.length; i<len; ++i) {
  7343. if(OpenLayers.Util.isEquivalentUrl(nodes.item(i).href,
  7344. this.theme)) {
  7345. addNode = false;
  7346. break;
  7347. }
  7348. }
  7349. // only add a new node if one with an equivalent url hasn't already
  7350. // been added
  7351. if(addNode) {
  7352. var cssNode = document.createElement('link');
  7353. cssNode.setAttribute('rel', 'stylesheet');
  7354. cssNode.setAttribute('type', 'text/css');
  7355. cssNode.setAttribute('href', this.theme);
  7356. document.getElementsByTagName('head')[0].appendChild(cssNode);
  7357. }
  7358. }
  7359. if (this.controls == null) { // default controls
  7360. this.controls = [];
  7361. if (OpenLayers.Control != null) { // running full or lite?
  7362. // Navigation or TouchNavigation depending on what is in build
  7363. if (OpenLayers.Control.Navigation) {
  7364. this.controls.push(new OpenLayers.Control.Navigation());
  7365. } else if (OpenLayers.Control.TouchNavigation) {
  7366. this.controls.push(new OpenLayers.Control.TouchNavigation());
  7367. }
  7368. if (OpenLayers.Control.Zoom) {
  7369. this.controls.push(new OpenLayers.Control.Zoom());
  7370. } else if (OpenLayers.Control.PanZoom) {
  7371. this.controls.push(new OpenLayers.Control.PanZoom());
  7372. }
  7373. if (OpenLayers.Control.ArgParser) {
  7374. this.controls.push(new OpenLayers.Control.ArgParser());
  7375. }
  7376. if (OpenLayers.Control.Attribution) {
  7377. this.controls.push(new OpenLayers.Control.Attribution());
  7378. }
  7379. }
  7380. }
  7381. for(var i=0, len=this.controls.length; i<len; i++) {
  7382. this.addControlToMap(this.controls[i]);
  7383. }
  7384. this.popups = [];
  7385. this.unloadDestroy = OpenLayers.Function.bind(this.destroy, this);
  7386. // always call map.destroy()
  7387. OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
  7388. // add any initial layers
  7389. if (options && options.layers) {
  7390. /**
  7391. * If you have set options.center, the map center property will be
  7392. * set at this point. However, since setCenter has not been called,
  7393. * addLayers gets confused. So we delete the map center in this
  7394. * case. Because the check below uses options.center, it will
  7395. * be properly set below.
  7396. */
  7397. delete this.center;
  7398. this.addLayers(options.layers);
  7399. // set center (and optionally zoom)
  7400. if (options.center && !this.getCenter()) {
  7401. // zoom can be undefined here
  7402. this.setCenter(options.center, options.zoom);
  7403. }
  7404. }
  7405. },
  7406. /**
  7407. * APIMethod: getViewport
  7408. * Get the DOMElement representing the view port.
  7409. *
  7410. * Returns:
  7411. * {DOMElement}
  7412. */
  7413. getViewport: function() {
  7414. return this.viewPortDiv;
  7415. },
  7416. /**
  7417. * APIMethod: render
  7418. * Render the map to a specified container.
  7419. *
  7420. * Parameters:
  7421. * div - {String|DOMElement} The container that the map should be rendered
  7422. * to. If different than the current container, the map viewport
  7423. * will be moved from the current to the new container.
  7424. */
  7425. render: function(div) {
  7426. this.div = OpenLayers.Util.getElement(div);
  7427. OpenLayers.Element.addClass(this.div, 'olMap');
  7428. this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);
  7429. this.div.appendChild(this.viewPortDiv);
  7430. this.updateSize();
  7431. },
  7432. /**
  7433. * Method: unloadDestroy
  7434. * Function that is called to destroy the map on page unload. stored here
  7435. * so that if map is manually destroyed, we can unregister this.
  7436. */
  7437. unloadDestroy: null,
  7438. /**
  7439. * Method: updateSizeDestroy
  7440. * When the map is destroyed, we need to stop listening to updateSize
  7441. * events: this method stores the function we need to unregister in
  7442. * non-IE browsers.
  7443. */
  7444. updateSizeDestroy: null,
  7445. /**
  7446. * APIMethod: destroy
  7447. * Destroy this map.
  7448. * Note that if you are using an application which removes a container
  7449. * of the map from the DOM, you need to ensure that you destroy the
  7450. * map *before* this happens; otherwise, the page unload handler
  7451. * will fail because the DOM elements that map.destroy() wants
  7452. * to clean up will be gone. (See
  7453. * http://trac.osgeo.org/openlayers/ticket/2277 for more information).
  7454. * This will apply to GeoExt and also to other applications which
  7455. * modify the DOM of the container of the OpenLayers Map.
  7456. */
  7457. destroy:function() {
  7458. // if unloadDestroy is null, we've already been destroyed
  7459. if (!this.unloadDestroy) {
  7460. return false;
  7461. }
  7462. // make sure panning doesn't continue after destruction
  7463. if(this.panTween) {
  7464. this.panTween.stop();
  7465. this.panTween = null;
  7466. }
  7467. // map has been destroyed. dont do it again!
  7468. OpenLayers.Event.stopObserving(window, 'unload', this.unloadDestroy);
  7469. this.unloadDestroy = null;
  7470. if (this.updateSizeDestroy) {
  7471. OpenLayers.Event.stopObserving(window, 'resize',
  7472. this.updateSizeDestroy);
  7473. } else {
  7474. this.events.unregister("resize", this, this.updateSize);
  7475. }
  7476. this.paddingForPopups = null;
  7477. if (this.controls != null) {
  7478. for (var i = this.controls.length - 1; i>=0; --i) {
  7479. this.controls[i].destroy();
  7480. }
  7481. this.controls = null;
  7482. }
  7483. if (this.layers != null) {
  7484. for (var i = this.layers.length - 1; i>=0; --i) {
  7485. //pass 'false' to destroy so that map wont try to set a new
  7486. // baselayer after each baselayer is removed
  7487. this.layers[i].destroy(false);
  7488. }
  7489. this.layers = null;
  7490. }
  7491. if (this.viewPortDiv) {
  7492. this.div.removeChild(this.viewPortDiv);
  7493. }
  7494. this.viewPortDiv = null;
  7495. if(this.eventListeners) {
  7496. this.events.un(this.eventListeners);
  7497. this.eventListeners = null;
  7498. }
  7499. this.events.destroy();
  7500. this.events = null;
  7501. this.options = null;
  7502. },
  7503. /**
  7504. * APIMethod: setOptions
  7505. * Change the map options
  7506. *
  7507. * Parameters:
  7508. * options - {Object} Hashtable of options to tag to the map
  7509. */
  7510. setOptions: function(options) {
  7511. var updatePxExtent = this.minPx &&
  7512. options.restrictedExtent != this.restrictedExtent;
  7513. OpenLayers.Util.extend(this, options);
  7514. // force recalculation of minPx and maxPx
  7515. updatePxExtent && this.moveTo(this.getCachedCenter(), this.zoom, {
  7516. forceZoomChange: true
  7517. });
  7518. },
  7519. /**
  7520. * APIMethod: getTileSize
  7521. * Get the tile size for the map
  7522. *
  7523. * Returns:
  7524. * {<OpenLayers.Size>}
  7525. */
  7526. getTileSize: function() {
  7527. return this.tileSize;
  7528. },
  7529. /**
  7530. * APIMethod: getBy
  7531. * Get a list of objects given a property and a match item.
  7532. *
  7533. * Parameters:
  7534. * array - {String} A property on the map whose value is an array.
  7535. * property - {String} A property on each item of the given array.
  7536. * match - {String | Object} A string to match. Can also be a regular
  7537. * expression literal or object. In addition, it can be any object
  7538. * with a method named test. For reqular expressions or other, if
  7539. * match.test(map[array][i][property]) evaluates to true, the item will
  7540. * be included in the array returned. If no items are found, an empty
  7541. * array is returned.
  7542. *
  7543. * Returns:
  7544. * {Array} An array of items where the given property matches the given
  7545. * criteria.
  7546. */
  7547. getBy: function(array, property, match) {
  7548. var test = (typeof match.test == "function");
  7549. var found = OpenLayers.Array.filter(this[array], function(item) {
  7550. return item[property] == match || (test && match.test(item[property]));
  7551. });
  7552. return found;
  7553. },
  7554. /**
  7555. * APIMethod: getLayersBy
  7556. * Get a list of layers with properties matching the given criteria.
  7557. *
  7558. * Parameters:
  7559. * property - {String} A layer property to be matched.
  7560. * match - {String | Object} A string to match. Can also be a regular
  7561. * expression literal or object. In addition, it can be any object
  7562. * with a method named test. For reqular expressions or other, if
  7563. * match.test(layer[property]) evaluates to true, the layer will be
  7564. * included in the array returned. If no layers are found, an empty
  7565. * array is returned.
  7566. *
  7567. * Returns:
  7568. * {Array(<OpenLayers.Layer>)} A list of layers matching the given criteria.
  7569. * An empty array is returned if no matches are found.
  7570. */
  7571. getLayersBy: function(property, match) {
  7572. return this.getBy("layers", property, match);
  7573. },
  7574. /**
  7575. * APIMethod: getLayersByName
  7576. * Get a list of layers with names matching the given name.
  7577. *
  7578. * Parameters:
  7579. * match - {String | Object} A layer name. The name can also be a regular
  7580. * expression literal or object. In addition, it can be any object
  7581. * with a method named test. For reqular expressions or other, if
  7582. * name.test(layer.name) evaluates to true, the layer will be included
  7583. * in the list of layers returned. If no layers are found, an empty
  7584. * array is returned.
  7585. *
  7586. * Returns:
  7587. * {Array(<OpenLayers.Layer>)} A list of layers matching the given name.
  7588. * An empty array is returned if no matches are found.
  7589. */
  7590. getLayersByName: function(match) {
  7591. return this.getLayersBy("name", match);
  7592. },
  7593. /**
  7594. * APIMethod: getLayersByClass
  7595. * Get a list of layers of a given class (CLASS_NAME).
  7596. *
  7597. * Parameters:
  7598. * match - {String | Object} A layer class name. The match can also be a
  7599. * regular expression literal or object. In addition, it can be any
  7600. * object with a method named test. For reqular expressions or other,
  7601. * if type.test(layer.CLASS_NAME) evaluates to true, the layer will
  7602. * be included in the list of layers returned. If no layers are
  7603. * found, an empty array is returned.
  7604. *
  7605. * Returns:
  7606. * {Array(<OpenLayers.Layer>)} A list of layers matching the given class.
  7607. * An empty array is returned if no matches are found.
  7608. */
  7609. getLayersByClass: function(match) {
  7610. return this.getLayersBy("CLASS_NAME", match);
  7611. },
  7612. /**
  7613. * APIMethod: getControlsBy
  7614. * Get a list of controls with properties matching the given criteria.
  7615. *
  7616. * Parameters:
  7617. * property - {String} A control property to be matched.
  7618. * match - {String | Object} A string to match. Can also be a regular
  7619. * expression literal or object. In addition, it can be any object
  7620. * with a method named test. For reqular expressions or other, if
  7621. * match.test(layer[property]) evaluates to true, the layer will be
  7622. * included in the array returned. If no layers are found, an empty
  7623. * array is returned.
  7624. *
  7625. * Returns:
  7626. * {Array(<OpenLayers.Control>)} A list of controls matching the given
  7627. * criteria. An empty array is returned if no matches are found.
  7628. */
  7629. getControlsBy: function(property, match) {
  7630. return this.getBy("controls", property, match);
  7631. },
  7632. /**
  7633. * APIMethod: getControlsByClass
  7634. * Get a list of controls of a given class (CLASS_NAME).
  7635. *
  7636. * Parameters:
  7637. * match - {String | Object} A control class name. The match can also be a
  7638. * regular expression literal or object. In addition, it can be any
  7639. * object with a method named test. For reqular expressions or other,
  7640. * if type.test(control.CLASS_NAME) evaluates to true, the control will
  7641. * be included in the list of controls returned. If no controls are
  7642. * found, an empty array is returned.
  7643. *
  7644. * Returns:
  7645. * {Array(<OpenLayers.Control>)} A list of controls matching the given class.
  7646. * An empty array is returned if no matches are found.
  7647. */
  7648. getControlsByClass: function(match) {
  7649. return this.getControlsBy("CLASS_NAME", match);
  7650. },
  7651. /********************************************************/
  7652. /* */
  7653. /* Layer Functions */
  7654. /* */
  7655. /* The following functions deal with adding and */
  7656. /* removing Layers to and from the Map */
  7657. /* */
  7658. /********************************************************/
  7659. /**
  7660. * APIMethod: getLayer
  7661. * Get a layer based on its id
  7662. *
  7663. * Parameters:
  7664. * id - {String} A layer id
  7665. *
  7666. * Returns:
  7667. * {<OpenLayers.Layer>} The Layer with the corresponding id from the map's
  7668. * layer collection, or null if not found.
  7669. */
  7670. getLayer: function(id) {
  7671. var foundLayer = null;
  7672. for (var i=0, len=this.layers.length; i<len; i++) {
  7673. var layer = this.layers[i];
  7674. if (layer.id == id) {
  7675. foundLayer = layer;
  7676. break;
  7677. }
  7678. }
  7679. return foundLayer;
  7680. },
  7681. /**
  7682. * Method: setLayerZIndex
  7683. *
  7684. * Parameters:
  7685. * layer - {<OpenLayers.Layer>}
  7686. * zIdx - {int}
  7687. */
  7688. setLayerZIndex: function (layer, zIdx) {
  7689. layer.setZIndex(
  7690. this.Z_INDEX_BASE[layer.isBaseLayer ? 'BaseLayer' : 'Overlay']
  7691. + zIdx * 5 );
  7692. },
  7693. /**
  7694. * Method: resetLayersZIndex
  7695. * Reset each layer's z-index based on layer's array index
  7696. */
  7697. resetLayersZIndex: function() {
  7698. for (var i=0, len=this.layers.length; i<len; i++) {
  7699. var layer = this.layers[i];
  7700. this.setLayerZIndex(layer, i);
  7701. }
  7702. },
  7703. /**
  7704. * APIMethod: addLayer
  7705. *
  7706. * Parameters:
  7707. * layer - {<OpenLayers.Layer>}
  7708. *
  7709. * Returns:
  7710. * {Boolean} True if the layer has been added to the map.
  7711. */
  7712. addLayer: function (layer) {
  7713. for(var i = 0, len = this.layers.length; i < len; i++) {
  7714. if (this.layers[i] == layer) {
  7715. return false;
  7716. }
  7717. }
  7718. if (this.events.triggerEvent("preaddlayer", {layer: layer}) === false) {
  7719. return false;
  7720. }
  7721. if(this.allOverlays) {
  7722. layer.isBaseLayer = false;
  7723. }
  7724. layer.div.className = "olLayerDiv";
  7725. layer.div.style.overflow = "";
  7726. this.setLayerZIndex(layer, this.layers.length);
  7727. if (layer.isFixed) {
  7728. this.viewPortDiv.appendChild(layer.div);
  7729. } else {
  7730. this.layerContainerDiv.appendChild(layer.div);
  7731. }
  7732. this.layers.push(layer);
  7733. layer.setMap(this);
  7734. if (layer.isBaseLayer || (this.allOverlays && !this.baseLayer)) {
  7735. if (this.baseLayer == null) {
  7736. // set the first baselaye we add as the baselayer
  7737. this.setBaseLayer(layer);
  7738. } else {
  7739. layer.setVisibility(false);
  7740. }
  7741. } else {
  7742. layer.redraw();
  7743. }
  7744. this.events.triggerEvent("addlayer", {layer: layer});
  7745. layer.events.triggerEvent("added", {map: this, layer: layer});
  7746. layer.afterAdd();
  7747. return true;
  7748. },
  7749. /**
  7750. * APIMethod: addLayers
  7751. *
  7752. * Parameters:
  7753. * layers - {Array(<OpenLayers.Layer>)}
  7754. */
  7755. addLayers: function (layers) {
  7756. for (var i=0, len=layers.length; i<len; i++) {
  7757. this.addLayer(layers[i]);
  7758. }
  7759. },
  7760. /**
  7761. * APIMethod: removeLayer
  7762. * Removes a layer from the map by removing its visual element (the
  7763. * layer.div property), then removing it from the map's internal list
  7764. * of layers, setting the layer's map property to null.
  7765. *
  7766. * a "removelayer" event is triggered.
  7767. *
  7768. * very worthy of mention is that simply removing a layer from a map
  7769. * will not cause the removal of any popups which may have been created
  7770. * by the layer. this is due to the fact that it was decided at some
  7771. * point that popups would not belong to layers. thus there is no way
  7772. * for us to know here to which layer the popup belongs.
  7773. *
  7774. * A simple solution to this is simply to call destroy() on the layer.
  7775. * the default OpenLayers.Layer class's destroy() function
  7776. * automatically takes care to remove itself from whatever map it has
  7777. * been attached to.
  7778. *
  7779. * The correct solution is for the layer itself to register an
  7780. * event-handler on "removelayer" and when it is called, if it
  7781. * recognizes itself as the layer being removed, then it cycles through
  7782. * its own personal list of popups, removing them from the map.
  7783. *
  7784. * Parameters:
  7785. * layer - {<OpenLayers.Layer>}
  7786. * setNewBaseLayer - {Boolean} Default is true
  7787. */
  7788. removeLayer: function(layer, setNewBaseLayer) {
  7789. if (this.events.triggerEvent("preremovelayer", {layer: layer}) === false) {
  7790. return;
  7791. }
  7792. if (setNewBaseLayer == null) {
  7793. setNewBaseLayer = true;
  7794. }
  7795. if (layer.isFixed) {
  7796. this.viewPortDiv.removeChild(layer.div);
  7797. } else {
  7798. this.layerContainerDiv.removeChild(layer.div);
  7799. }
  7800. OpenLayers.Util.removeItem(this.layers, layer);
  7801. layer.removeMap(this);
  7802. layer.map = null;
  7803. // if we removed the base layer, need to set a new one
  7804. if(this.baseLayer == layer) {
  7805. this.baseLayer = null;
  7806. if(setNewBaseLayer) {
  7807. for(var i=0, len=this.layers.length; i<len; i++) {
  7808. var iLayer = this.layers[i];
  7809. if (iLayer.isBaseLayer || this.allOverlays) {
  7810. this.setBaseLayer(iLayer);
  7811. break;
  7812. }
  7813. }
  7814. }
  7815. }
  7816. this.resetLayersZIndex();
  7817. this.events.triggerEvent("removelayer", {layer: layer});
  7818. layer.events.triggerEvent("removed", {map: this, layer: layer});
  7819. },
  7820. /**
  7821. * APIMethod: getNumLayers
  7822. *
  7823. * Returns:
  7824. * {Int} The number of layers attached to the map.
  7825. */
  7826. getNumLayers: function () {
  7827. return this.layers.length;
  7828. },
  7829. /**
  7830. * APIMethod: getLayerIndex
  7831. *
  7832. * Parameters:
  7833. * layer - {<OpenLayers.Layer>}
  7834. *
  7835. * Returns:
  7836. * {Integer} The current (zero-based) index of the given layer in the map's
  7837. * layer stack. Returns -1 if the layer isn't on the map.
  7838. */
  7839. getLayerIndex: function (layer) {
  7840. return OpenLayers.Util.indexOf(this.layers, layer);
  7841. },
  7842. /**
  7843. * APIMethod: setLayerIndex
  7844. * Move the given layer to the specified (zero-based) index in the layer
  7845. * list, changing its z-index in the map display. Use
  7846. * map.getLayerIndex() to find out the current index of a layer. Note
  7847. * that this cannot (or at least should not) be effectively used to
  7848. * raise base layers above overlays.
  7849. *
  7850. * Parameters:
  7851. * layer - {<OpenLayers.Layer>}
  7852. * idx - {int}
  7853. */
  7854. setLayerIndex: function (layer, idx) {
  7855. var base = this.getLayerIndex(layer);
  7856. if (idx < 0) {
  7857. idx = 0;
  7858. } else if (idx > this.layers.length) {
  7859. idx = this.layers.length;
  7860. }
  7861. if (base != idx) {
  7862. this.layers.splice(base, 1);
  7863. this.layers.splice(idx, 0, layer);
  7864. for (var i=0, len=this.layers.length; i<len; i++) {
  7865. this.setLayerZIndex(this.layers[i], i);
  7866. }
  7867. this.events.triggerEvent("changelayer", {
  7868. layer: layer, property: "order"
  7869. });
  7870. if(this.allOverlays) {
  7871. if(idx === 0) {
  7872. this.setBaseLayer(layer);
  7873. } else if(this.baseLayer !== this.layers[0]) {
  7874. this.setBaseLayer(this.layers[0]);
  7875. }
  7876. }
  7877. }
  7878. },
  7879. /**
  7880. * APIMethod: raiseLayer
  7881. * Change the index of the given layer by delta. If delta is positive,
  7882. * the layer is moved up the map's layer stack; if delta is negative,
  7883. * the layer is moved down. Again, note that this cannot (or at least
  7884. * should not) be effectively used to raise base layers above overlays.
  7885. *
  7886. * Paremeters:
  7887. * layer - {<OpenLayers.Layer>}
  7888. * delta - {int}
  7889. */
  7890. raiseLayer: function (layer, delta) {
  7891. var idx = this.getLayerIndex(layer) + delta;
  7892. this.setLayerIndex(layer, idx);
  7893. },
  7894. /**
  7895. * APIMethod: setBaseLayer
  7896. * Allows user to specify one of the currently-loaded layers as the Map's
  7897. * new base layer.
  7898. *
  7899. * Parameters:
  7900. * newBaseLayer - {<OpenLayers.Layer>}
  7901. */
  7902. setBaseLayer: function(newBaseLayer) {
  7903. if (newBaseLayer != this.baseLayer) {
  7904. // ensure newBaseLayer is already loaded
  7905. if (OpenLayers.Util.indexOf(this.layers, newBaseLayer) != -1) {
  7906. // preserve center and scale when changing base layers
  7907. var center = this.getCachedCenter();
  7908. var newResolution = OpenLayers.Util.getResolutionFromScale(
  7909. this.getScale(), newBaseLayer.units
  7910. );
  7911. // make the old base layer invisible
  7912. if (this.baseLayer != null && !this.allOverlays) {
  7913. this.baseLayer.setVisibility(false);
  7914. }
  7915. // set new baselayer
  7916. this.baseLayer = newBaseLayer;
  7917. if(!this.allOverlays || this.baseLayer.visibility) {
  7918. this.baseLayer.setVisibility(true);
  7919. // Layer may previously have been visible but not in range.
  7920. // In this case we need to redraw it to make it visible.
  7921. if (this.baseLayer.inRange === false) {
  7922. this.baseLayer.redraw();
  7923. }
  7924. }
  7925. // recenter the map
  7926. if (center != null) {
  7927. // new zoom level derived from old scale
  7928. var newZoom = this.getZoomForResolution(
  7929. newResolution || this.resolution, true
  7930. );
  7931. // zoom and force zoom change
  7932. this.setCenter(center, newZoom, false, true);
  7933. }
  7934. this.events.triggerEvent("changebaselayer", {
  7935. layer: this.baseLayer
  7936. });
  7937. }
  7938. }
  7939. },
  7940. /********************************************************/
  7941. /* */
  7942. /* Control Functions */
  7943. /* */
  7944. /* The following functions deal with adding and */
  7945. /* removing Controls to and from the Map */
  7946. /* */
  7947. /********************************************************/
  7948. /**
  7949. * APIMethod: addControl
  7950. * Add the passed over control to the map. Optionally
  7951. * position the control at the given pixel.
  7952. *
  7953. * Parameters:
  7954. * control - {<OpenLayers.Control>}
  7955. * px - {<OpenLayers.Pixel>}
  7956. */
  7957. addControl: function (control, px) {
  7958. this.controls.push(control);
  7959. this.addControlToMap(control, px);
  7960. },
  7961. /**
  7962. * APIMethod: addControls
  7963. * Add all of the passed over controls to the map.
  7964. * You can pass over an optional second array
  7965. * with pixel-objects to position the controls.
  7966. * The indices of the two arrays should match and
  7967. * you can add null as pixel for those controls
  7968. * you want to be autopositioned.
  7969. *
  7970. * Parameters:
  7971. * controls - {Array(<OpenLayers.Control>)}
  7972. * pixels - {Array(<OpenLayers.Pixel>)}
  7973. */
  7974. addControls: function (controls, pixels) {
  7975. var pxs = (arguments.length === 1) ? [] : pixels;
  7976. for (var i=0, len=controls.length; i<len; i++) {
  7977. var ctrl = controls[i];
  7978. var px = (pxs[i]) ? pxs[i] : null;
  7979. this.addControl( ctrl, px );
  7980. }
  7981. },
  7982. /**
  7983. * Method: addControlToMap
  7984. *
  7985. * Parameters:
  7986. *
  7987. * control - {<OpenLayers.Control>}
  7988. * px - {<OpenLayers.Pixel>}
  7989. */
  7990. addControlToMap: function (control, px) {
  7991. // If a control doesn't have a div at this point, it belongs in the
  7992. // viewport.
  7993. control.outsideViewport = (control.div != null);
  7994. // If the map has a displayProjection, and the control doesn't, set
  7995. // the display projection.
  7996. if (this.displayProjection && !control.displayProjection) {
  7997. control.displayProjection = this.displayProjection;
  7998. }
  7999. control.setMap(this);
  8000. var div = control.draw(px);
  8001. if (div) {
  8002. if(!control.outsideViewport) {
  8003. div.style.zIndex = this.Z_INDEX_BASE['Control'] +
  8004. this.controls.length;
  8005. this.viewPortDiv.appendChild( div );
  8006. }
  8007. }
  8008. if(control.autoActivate) {
  8009. control.activate();
  8010. }
  8011. },
  8012. /**
  8013. * APIMethod: getControl
  8014. *
  8015. * Parameters:
  8016. * id - {String} ID of the control to return.
  8017. *
  8018. * Returns:
  8019. * {<OpenLayers.Control>} The control from the map's list of controls
  8020. * which has a matching 'id'. If none found,
  8021. * returns null.
  8022. */
  8023. getControl: function (id) {
  8024. var returnControl = null;
  8025. for(var i=0, len=this.controls.length; i<len; i++) {
  8026. var control = this.controls[i];
  8027. if (control.id == id) {
  8028. returnControl = control;
  8029. break;
  8030. }
  8031. }
  8032. return returnControl;
  8033. },
  8034. /**
  8035. * APIMethod: removeControl
  8036. * Remove a control from the map. Removes the control both from the map
  8037. * object's internal array of controls, as well as from the map's
  8038. * viewPort (assuming the control was not added outsideViewport)
  8039. *
  8040. * Parameters:
  8041. * control - {<OpenLayers.Control>} The control to remove.
  8042. */
  8043. removeControl: function (control) {
  8044. //make sure control is non-null and actually part of our map
  8045. if ( (control) && (control == this.getControl(control.id)) ) {
  8046. if (control.div && (control.div.parentNode == this.viewPortDiv)) {
  8047. this.viewPortDiv.removeChild(control.div);
  8048. }
  8049. OpenLayers.Util.removeItem(this.controls, control);
  8050. }
  8051. },
  8052. /********************************************************/
  8053. /* */
  8054. /* Popup Functions */
  8055. /* */
  8056. /* The following functions deal with adding and */
  8057. /* removing Popups to and from the Map */
  8058. /* */
  8059. /********************************************************/
  8060. /**
  8061. * APIMethod: addPopup
  8062. *
  8063. * Parameters:
  8064. * popup - {<OpenLayers.Popup>}
  8065. * exclusive - {Boolean} If true, closes all other popups first
  8066. */
  8067. addPopup: function(popup, exclusive) {
  8068. if (exclusive) {
  8069. //remove all other popups from screen
  8070. for (var i = this.popups.length - 1; i >= 0; --i) {
  8071. this.removePopup(this.popups[i]);
  8072. }
  8073. }
  8074. popup.map = this;
  8075. this.popups.push(popup);
  8076. var popupDiv = popup.draw();
  8077. if (popupDiv) {
  8078. popupDiv.style.zIndex = this.Z_INDEX_BASE['Popup'] +
  8079. this.popups.length;
  8080. this.layerContainerDiv.appendChild(popupDiv);
  8081. }
  8082. },
  8083. /**
  8084. * APIMethod: removePopup
  8085. *
  8086. * Parameters:
  8087. * popup - {<OpenLayers.Popup>}
  8088. */
  8089. removePopup: function(popup) {
  8090. OpenLayers.Util.removeItem(this.popups, popup);
  8091. if (popup.div) {
  8092. try { this.layerContainerDiv.removeChild(popup.div); }
  8093. catch (e) { } // Popups sometimes apparently get disconnected
  8094. // from the layerContainerDiv, and cause complaints.
  8095. }
  8096. popup.map = null;
  8097. },
  8098. /********************************************************/
  8099. /* */
  8100. /* Container Div Functions */
  8101. /* */
  8102. /* The following functions deal with the access to */
  8103. /* and maintenance of the size of the container div */
  8104. /* */
  8105. /********************************************************/
  8106. /**
  8107. * APIMethod: getSize
  8108. *
  8109. * Returns:
  8110. * {<OpenLayers.Size>} An <OpenLayers.Size> object that represents the
  8111. * size, in pixels, of the div into which OpenLayers
  8112. * has been loaded.
  8113. * Note - A clone() of this locally cached variable is
  8114. * returned, so as not to allow users to modify it.
  8115. */
  8116. getSize: function () {
  8117. var size = null;
  8118. if (this.size != null) {
  8119. size = this.size.clone();
  8120. }
  8121. return size;
  8122. },
  8123. /**
  8124. * APIMethod: updateSize
  8125. * This function should be called by any external code which dynamically
  8126. * changes the size of the map div (because mozilla wont let us catch
  8127. * the "onresize" for an element)
  8128. */
  8129. updateSize: function() {
  8130. // the div might have moved on the page, also
  8131. var newSize = this.getCurrentSize();
  8132. if (newSize && !isNaN(newSize.h) && !isNaN(newSize.w)) {
  8133. this.events.clearMouseCache();
  8134. var oldSize = this.getSize();
  8135. if (oldSize == null) {
  8136. this.size = oldSize = newSize;
  8137. }
  8138. if (!newSize.equals(oldSize)) {
  8139. // store the new size
  8140. this.size = newSize;
  8141. //notify layers of mapresize
  8142. for(var i=0, len=this.layers.length; i<len; i++) {
  8143. this.layers[i].onMapResize();
  8144. }
  8145. var center = this.getCachedCenter();
  8146. if (this.baseLayer != null && center != null) {
  8147. var zoom = this.getZoom();
  8148. this.zoom = null;
  8149. this.setCenter(center, zoom);
  8150. }
  8151. }
  8152. }
  8153. },
  8154. /**
  8155. * Method: getCurrentSize
  8156. *
  8157. * Returns:
  8158. * {<OpenLayers.Size>} A new <OpenLayers.Size> object with the dimensions
  8159. * of the map div
  8160. */
  8161. getCurrentSize: function() {
  8162. var size = new OpenLayers.Size(this.div.clientWidth,
  8163. this.div.clientHeight);
  8164. if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
  8165. size.w = this.div.offsetWidth;
  8166. size.h = this.div.offsetHeight;
  8167. }
  8168. if (size.w == 0 && size.h == 0 || isNaN(size.w) && isNaN(size.h)) {
  8169. size.w = parseInt(this.div.style.width);
  8170. size.h = parseInt(this.div.style.height);
  8171. }
  8172. return size;
  8173. },
  8174. /**
  8175. * Method: calculateBounds
  8176. *
  8177. * Parameters:
  8178. * center - {<OpenLayers.LonLat>} Default is this.getCenter()
  8179. * resolution - {float} Default is this.getResolution()
  8180. *
  8181. * Returns:
  8182. * {<OpenLayers.Bounds>} A bounds based on resolution, center, and
  8183. * current mapsize.
  8184. */
  8185. calculateBounds: function(center, resolution) {
  8186. var extent = null;
  8187. if (center == null) {
  8188. center = this.getCachedCenter();
  8189. }
  8190. if (resolution == null) {
  8191. resolution = this.getResolution();
  8192. }
  8193. if ((center != null) && (resolution != null)) {
  8194. var halfWDeg = (this.size.w * resolution) / 2;
  8195. var halfHDeg = (this.size.h * resolution) / 2;
  8196. extent = new OpenLayers.Bounds(center.lon - halfWDeg,
  8197. center.lat - halfHDeg,
  8198. center.lon + halfWDeg,
  8199. center.lat + halfHDeg);
  8200. }
  8201. return extent;
  8202. },
  8203. /********************************************************/
  8204. /* */
  8205. /* Zoom, Center, Pan Functions */
  8206. /* */
  8207. /* The following functions handle the validation, */
  8208. /* getting and setting of the Zoom Level and Center */
  8209. /* as well as the panning of the Map */
  8210. /* */
  8211. /********************************************************/
  8212. /**
  8213. * APIMethod: getCenter
  8214. *
  8215. * Returns:
  8216. * {<OpenLayers.LonLat>}
  8217. */
  8218. getCenter: function () {
  8219. var center = null;
  8220. var cachedCenter = this.getCachedCenter();
  8221. if (cachedCenter) {
  8222. center = cachedCenter.clone();
  8223. }
  8224. return center;
  8225. },
  8226. /**
  8227. * Method: getCachedCenter
  8228. *
  8229. * Returns:
  8230. * {<OpenLayers.LonLat>}
  8231. */
  8232. getCachedCenter: function() {
  8233. if (!this.center && this.size) {
  8234. this.center = this.getLonLatFromViewPortPx({
  8235. x: this.size.w / 2,
  8236. y: this.size.h / 2
  8237. });
  8238. }
  8239. return this.center;
  8240. },
  8241. /**
  8242. * APIMethod: getZoom
  8243. *
  8244. * Returns:
  8245. * {Integer}
  8246. */
  8247. getZoom: function () {
  8248. return this.zoom;
  8249. },
  8250. /**
  8251. * APIMethod: pan
  8252. * Allows user to pan by a value of screen pixels
  8253. *
  8254. * Parameters:
  8255. * dx - {Integer}
  8256. * dy - {Integer}
  8257. * options - {Object} Options to configure panning:
  8258. * - *animate* {Boolean} Use panTo instead of setCenter. Default is true.
  8259. * - *dragging* {Boolean} Call setCenter with dragging true. Default is
  8260. * false.
  8261. */
  8262. pan: function(dx, dy, options) {
  8263. options = OpenLayers.Util.applyDefaults(options, {
  8264. animate: true,
  8265. dragging: false
  8266. });
  8267. if (options.dragging) {
  8268. if (dx != 0 || dy != 0) {
  8269. this.moveByPx(dx, dy);
  8270. }
  8271. } else {
  8272. // getCenter
  8273. var centerPx = this.getViewPortPxFromLonLat(this.getCachedCenter());
  8274. // adjust
  8275. var newCenterPx = centerPx.add(dx, dy);
  8276. if (this.dragging || !newCenterPx.equals(centerPx)) {
  8277. var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
  8278. if (options.animate) {
  8279. this.panTo(newCenterLonLat);
  8280. } else {
  8281. this.moveTo(newCenterLonLat);
  8282. if(this.dragging) {
  8283. this.dragging = false;
  8284. this.events.triggerEvent("moveend");
  8285. }
  8286. }
  8287. }
  8288. }
  8289. },
  8290. /**
  8291. * APIMethod: panTo
  8292. * Allows user to pan to a new lonlat
  8293. * If the new lonlat is in the current extent the map will slide smoothly
  8294. *
  8295. * Parameters:
  8296. * lonlat - {<OpenLayers.LonLat>}
  8297. */
  8298. panTo: function(lonlat) {
  8299. if (this.panMethod && this.getExtent().scale(this.panRatio).containsLonLat(lonlat)) {
  8300. if (!this.panTween) {
  8301. this.panTween = new OpenLayers.Tween(this.panMethod);
  8302. }
  8303. var center = this.getCachedCenter();
  8304. // center will not change, don't do nothing
  8305. if (lonlat.equals(center)) {
  8306. return;
  8307. }
  8308. var from = this.getPixelFromLonLat(center);
  8309. var to = this.getPixelFromLonLat(lonlat);
  8310. var vector = { x: to.x - from.x, y: to.y - from.y };
  8311. var last = { x: 0, y: 0 };
  8312. this.panTween.start( { x: 0, y: 0 }, vector, this.panDuration, {
  8313. callbacks: {
  8314. eachStep: OpenLayers.Function.bind(function(px) {
  8315. var x = px.x - last.x,
  8316. y = px.y - last.y;
  8317. this.moveByPx(x, y);
  8318. last.x = Math.round(px.x);
  8319. last.y = Math.round(px.y);
  8320. }, this),
  8321. done: OpenLayers.Function.bind(function(px) {
  8322. this.moveTo(lonlat);
  8323. this.dragging = false;
  8324. this.events.triggerEvent("moveend");
  8325. }, this)
  8326. }
  8327. });
  8328. } else {
  8329. this.setCenter(lonlat);
  8330. }
  8331. },
  8332. /**
  8333. * APIMethod: setCenter
  8334. * Set the map center (and optionally, the zoom level).
  8335. *
  8336. * Parameters:
  8337. * lonlat - {<OpenLayers.LonLat>|Array} The new center location.
  8338. * If provided as array, the first value is the x coordinate,
  8339. * and the 2nd value is the y coordinate.
  8340. * zoom - {Integer} Optional zoom level.
  8341. * dragging - {Boolean} Specifies whether or not to trigger
  8342. * movestart/end events
  8343. * forceZoomChange - {Boolean} Specifies whether or not to trigger zoom
  8344. * change events (needed on baseLayer change)
  8345. *
  8346. * TBD: reconsider forceZoomChange in 3.0
  8347. */
  8348. setCenter: function(lonlat, zoom, dragging, forceZoomChange) {
  8349. this.panTween && this.panTween.stop();
  8350. this.moveTo(lonlat, zoom, {
  8351. 'dragging': dragging,
  8352. 'forceZoomChange': forceZoomChange
  8353. });
  8354. },
  8355. /**
  8356. * Method: moveByPx
  8357. * Drag the map by pixels.
  8358. *
  8359. * Parameters:
  8360. * dx - {Number}
  8361. * dy - {Number}
  8362. */
  8363. moveByPx: function(dx, dy) {
  8364. var hw = this.size.w / 2;
  8365. var hh = this.size.h / 2;
  8366. var x = hw + dx;
  8367. var y = hh + dy;
  8368. var wrapDateLine = this.baseLayer.wrapDateLine;
  8369. var xRestriction = 0;
  8370. var yRestriction = 0;
  8371. if (this.restrictedExtent) {
  8372. xRestriction = hw;
  8373. yRestriction = hh;
  8374. // wrapping the date line makes no sense for restricted extents
  8375. wrapDateLine = false;
  8376. }
  8377. dx = wrapDateLine ||
  8378. x <= this.maxPx.x - xRestriction &&
  8379. x >= this.minPx.x + xRestriction ? Math.round(dx) : 0;
  8380. dy = y <= this.maxPx.y - yRestriction &&
  8381. y >= this.minPx.y + yRestriction ? Math.round(dy) : 0;
  8382. if (dx || dy) {
  8383. if (!this.dragging) {
  8384. this.dragging = true;
  8385. this.events.triggerEvent("movestart");
  8386. }
  8387. this.center = null;
  8388. if (dx) {
  8389. this.layerContainerDiv.style.left =
  8390. parseInt(this.layerContainerDiv.style.left) - dx + "px";
  8391. this.minPx.x -= dx;
  8392. this.maxPx.x -= dx;
  8393. }
  8394. if (dy) {
  8395. this.layerContainerDiv.style.top =
  8396. parseInt(this.layerContainerDiv.style.top) - dy + "px";
  8397. this.minPx.y -= dy;
  8398. this.maxPx.y -= dy;
  8399. }
  8400. var layer, i, len;
  8401. for (i=0, len=this.layers.length; i<len; ++i) {
  8402. layer = this.layers[i];
  8403. if (layer.visibility &&
  8404. (layer === this.baseLayer || layer.inRange)) {
  8405. layer.moveByPx(dx, dy);
  8406. layer.events.triggerEvent("move");
  8407. }
  8408. }
  8409. this.events.triggerEvent("move");
  8410. }
  8411. },
  8412. /**
  8413. * Method: adjustZoom
  8414. *
  8415. * Parameters:
  8416. * zoom - {Number} The zoom level to adjust
  8417. *
  8418. * Returns:
  8419. * {Integer} Adjusted zoom level that shows a map not wider than its
  8420. * <baseLayer>'s maxExtent.
  8421. */
  8422. adjustZoom: function(zoom) {
  8423. var resolution, resolutions = this.baseLayer.resolutions,
  8424. maxResolution = this.getMaxExtent().getWidth() / this.size.w;
  8425. if (this.getResolutionForZoom(zoom) > maxResolution) {
  8426. for (var i=zoom|0, ii=resolutions.length; i<ii; ++i) {
  8427. if (resolutions[i] <= maxResolution) {
  8428. zoom = i;
  8429. break;
  8430. }
  8431. }
  8432. }
  8433. return zoom;
  8434. },
  8435. /**
  8436. * Method: moveTo
  8437. *
  8438. * Parameters:
  8439. * lonlat - {<OpenLayers.LonLat>}
  8440. * zoom - {Integer}
  8441. * options - {Object}
  8442. */
  8443. moveTo: function(lonlat, zoom, options) {
  8444. if (lonlat != null && !(lonlat instanceof OpenLayers.LonLat)) {
  8445. lonlat = new OpenLayers.LonLat(lonlat);
  8446. }
  8447. if (!options) {
  8448. options = {};
  8449. }
  8450. if (zoom != null) {
  8451. zoom = parseFloat(zoom);
  8452. if (!this.fractionalZoom) {
  8453. zoom = Math.round(zoom);
  8454. }
  8455. }
  8456. if (this.baseLayer.wrapDateLine) {
  8457. var requestedZoom = zoom;
  8458. zoom = this.adjustZoom(zoom);
  8459. if (zoom !== requestedZoom) {
  8460. // zoom was adjusted, so keep old lonlat to avoid panning
  8461. lonlat = this.getCenter();
  8462. }
  8463. }
  8464. // dragging is false by default
  8465. var dragging = options.dragging || this.dragging;
  8466. // forceZoomChange is false by default
  8467. var forceZoomChange = options.forceZoomChange;
  8468. if (!this.getCachedCenter() && !this.isValidLonLat(lonlat)) {
  8469. lonlat = this.maxExtent.getCenterLonLat();
  8470. this.center = lonlat.clone();
  8471. }
  8472. if(this.restrictedExtent != null) {
  8473. // In 3.0, decide if we want to change interpretation of maxExtent.
  8474. if(lonlat == null) {
  8475. lonlat = this.center;
  8476. }
  8477. if(zoom == null) {
  8478. zoom = this.getZoom();
  8479. }
  8480. var resolution = this.getResolutionForZoom(zoom);
  8481. var extent = this.calculateBounds(lonlat, resolution);
  8482. if(!this.restrictedExtent.containsBounds(extent)) {
  8483. var maxCenter = this.restrictedExtent.getCenterLonLat();
  8484. if(extent.getWidth() > this.restrictedExtent.getWidth()) {
  8485. lonlat = new OpenLayers.LonLat(maxCenter.lon, lonlat.lat);
  8486. } else if(extent.left < this.restrictedExtent.left) {
  8487. lonlat = lonlat.add(this.restrictedExtent.left -
  8488. extent.left, 0);
  8489. } else if(extent.right > this.restrictedExtent.right) {
  8490. lonlat = lonlat.add(this.restrictedExtent.right -
  8491. extent.right, 0);
  8492. }
  8493. if(extent.getHeight() > this.restrictedExtent.getHeight()) {
  8494. lonlat = new OpenLayers.LonLat(lonlat.lon, maxCenter.lat);
  8495. } else if(extent.bottom < this.restrictedExtent.bottom) {
  8496. lonlat = lonlat.add(0, this.restrictedExtent.bottom -
  8497. extent.bottom);
  8498. }
  8499. else if(extent.top > this.restrictedExtent.top) {
  8500. lonlat = lonlat.add(0, this.restrictedExtent.top -
  8501. extent.top);
  8502. }
  8503. }
  8504. }
  8505. var zoomChanged = forceZoomChange || (
  8506. (this.isValidZoomLevel(zoom)) &&
  8507. (zoom != this.getZoom()) );
  8508. var centerChanged = (this.isValidLonLat(lonlat)) &&
  8509. (!lonlat.equals(this.center));
  8510. // if neither center nor zoom will change, no need to do anything
  8511. if (zoomChanged || centerChanged || dragging) {
  8512. dragging || this.events.triggerEvent("movestart");
  8513. if (centerChanged) {
  8514. if (!zoomChanged && this.center) {
  8515. // if zoom hasnt changed, just slide layerContainer
  8516. // (must be done before setting this.center to new value)
  8517. this.centerLayerContainer(lonlat);
  8518. }
  8519. this.center = lonlat.clone();
  8520. }
  8521. var res = zoomChanged ?
  8522. this.getResolutionForZoom(zoom) : this.getResolution();
  8523. // (re)set the layerContainerDiv's location
  8524. if (zoomChanged || this.layerContainerOrigin == null) {
  8525. this.layerContainerOrigin = this.getCachedCenter();
  8526. this.layerContainerDiv.style.left = "0px";
  8527. this.layerContainerDiv.style.top = "0px";
  8528. var maxExtent = this.getMaxExtent({restricted: true});
  8529. var maxExtentCenter = maxExtent.getCenterLonLat();
  8530. var lonDelta = this.center.lon - maxExtentCenter.lon;
  8531. var latDelta = maxExtentCenter.lat - this.center.lat;
  8532. var extentWidth = Math.round(maxExtent.getWidth() / res);
  8533. var extentHeight = Math.round(maxExtent.getHeight() / res);
  8534. this.minPx = {
  8535. x: (this.size.w - extentWidth) / 2 - lonDelta / res,
  8536. y: (this.size.h - extentHeight) / 2 - latDelta / res
  8537. };
  8538. this.maxPx = {
  8539. x: this.minPx.x + Math.round(maxExtent.getWidth() / res),
  8540. y: this.minPx.y + Math.round(maxExtent.getHeight() / res)
  8541. };
  8542. }
  8543. if (zoomChanged) {
  8544. this.zoom = zoom;
  8545. this.resolution = res;
  8546. }
  8547. var bounds = this.getExtent();
  8548. //send the move call to the baselayer and all the overlays
  8549. if(this.baseLayer.visibility) {
  8550. this.baseLayer.moveTo(bounds, zoomChanged, options.dragging);
  8551. options.dragging || this.baseLayer.events.triggerEvent(
  8552. "moveend", {zoomChanged: zoomChanged}
  8553. );
  8554. }
  8555. bounds = this.baseLayer.getExtent();
  8556. for (var i=this.layers.length-1; i>=0; --i) {
  8557. var layer = this.layers[i];
  8558. if (layer !== this.baseLayer && !layer.isBaseLayer) {
  8559. var inRange = layer.calculateInRange();
  8560. if (layer.inRange != inRange) {
  8561. // the inRange property has changed. If the layer is
  8562. // no longer in range, we turn it off right away. If
  8563. // the layer is no longer out of range, the moveTo
  8564. // call below will turn on the layer.
  8565. layer.inRange = inRange;
  8566. if (!inRange) {
  8567. layer.display(false);
  8568. }
  8569. this.events.triggerEvent("changelayer", {
  8570. layer: layer, property: "visibility"
  8571. });
  8572. }
  8573. if (inRange && layer.visibility) {
  8574. layer.moveTo(bounds, zoomChanged, options.dragging);
  8575. options.dragging || layer.events.triggerEvent(
  8576. "moveend", {zoomChanged: zoomChanged}
  8577. );
  8578. }
  8579. }
  8580. }
  8581. this.events.triggerEvent("move");
  8582. dragging || this.events.triggerEvent("moveend");
  8583. if (zoomChanged) {
  8584. //redraw popups
  8585. for (var i=0, len=this.popups.length; i<len; i++) {
  8586. this.popups[i].updatePosition();
  8587. }
  8588. this.events.triggerEvent("zoomend");
  8589. }
  8590. }
  8591. },
  8592. /**
  8593. * Method: centerLayerContainer
  8594. * This function takes care to recenter the layerContainerDiv.
  8595. *
  8596. * Parameters:
  8597. * lonlat - {<OpenLayers.LonLat>}
  8598. */
  8599. centerLayerContainer: function (lonlat) {
  8600. var originPx = this.getViewPortPxFromLonLat(this.layerContainerOrigin);
  8601. var newPx = this.getViewPortPxFromLonLat(lonlat);
  8602. if ((originPx != null) && (newPx != null)) {
  8603. var oldLeft = parseInt(this.layerContainerDiv.style.left);
  8604. var oldTop = parseInt(this.layerContainerDiv.style.top);
  8605. var newLeft = Math.round(originPx.x - newPx.x);
  8606. var newTop = Math.round(originPx.y - newPx.y);
  8607. this.layerContainerDiv.style.left = newLeft + "px";
  8608. this.layerContainerDiv.style.top = newTop + "px";
  8609. var dx = oldLeft - newLeft;
  8610. var dy = oldTop - newTop;
  8611. this.minPx.x -= dx;
  8612. this.maxPx.x -= dx;
  8613. this.minPx.y -= dy;
  8614. this.maxPx.y -= dy;
  8615. }
  8616. },
  8617. /**
  8618. * Method: isValidZoomLevel
  8619. *
  8620. * Parameters:
  8621. * zoomLevel - {Integer}
  8622. *
  8623. * Returns:
  8624. * {Boolean} Whether or not the zoom level passed in is non-null and
  8625. * within the min/max range of zoom levels.
  8626. */
  8627. isValidZoomLevel: function(zoomLevel) {
  8628. return ( (zoomLevel != null) &&
  8629. (zoomLevel >= 0) &&
  8630. (zoomLevel < this.getNumZoomLevels()) );
  8631. },
  8632. /**
  8633. * Method: isValidLonLat
  8634. *
  8635. * Parameters:
  8636. * lonlat - {<OpenLayers.LonLat>}
  8637. *
  8638. * Returns:
  8639. * {Boolean} Whether or not the lonlat passed in is non-null and within
  8640. * the maxExtent bounds
  8641. */
  8642. isValidLonLat: function(lonlat) {
  8643. var valid = false;
  8644. if (lonlat != null) {
  8645. var maxExtent = this.getMaxExtent();
  8646. var worldBounds = this.baseLayer.wrapDateLine && maxExtent;
  8647. valid = maxExtent.containsLonLat(lonlat, {worldBounds: worldBounds});
  8648. }
  8649. return valid;
  8650. },
  8651. /********************************************************/
  8652. /* */
  8653. /* Layer Options */
  8654. /* */
  8655. /* Accessor functions to Layer Options parameters */
  8656. /* */
  8657. /********************************************************/
  8658. /**
  8659. * APIMethod: getProjection
  8660. * This method returns a string representing the projection. In
  8661. * the case of projection support, this will be the srsCode which
  8662. * is loaded -- otherwise it will simply be the string value that
  8663. * was passed to the projection at startup.
  8664. *
  8665. * FIXME: In 3.0, we will remove getProjectionObject, and instead
  8666. * return a Projection object from this function.
  8667. *
  8668. * Returns:
  8669. * {String} The Projection string from the base layer or null.
  8670. */
  8671. getProjection: function() {
  8672. var projection = this.getProjectionObject();
  8673. return projection ? projection.getCode() : null;
  8674. },
  8675. /**
  8676. * APIMethod: getProjectionObject
  8677. * Returns the projection obect from the baselayer.
  8678. *
  8679. * Returns:
  8680. * {<OpenLayers.Projection>} The Projection of the base layer.
  8681. */
  8682. getProjectionObject: function() {
  8683. var projection = null;
  8684. if (this.baseLayer != null) {
  8685. projection = this.baseLayer.projection;
  8686. }
  8687. return projection;
  8688. },
  8689. /**
  8690. * APIMethod: getMaxResolution
  8691. *
  8692. * Returns:
  8693. * {String} The Map's Maximum Resolution
  8694. */
  8695. getMaxResolution: function() {
  8696. var maxResolution = null;
  8697. if (this.baseLayer != null) {
  8698. maxResolution = this.baseLayer.maxResolution;
  8699. }
  8700. return maxResolution;
  8701. },
  8702. /**
  8703. * APIMethod: getMaxExtent
  8704. *
  8705. * Parameters:
  8706. * options - {Object}
  8707. *
  8708. * Allowed Options:
  8709. * restricted - {Boolean} If true, returns restricted extent (if it is
  8710. * available.)
  8711. *
  8712. * Returns:
  8713. * {<OpenLayers.Bounds>} The maxExtent property as set on the current
  8714. * baselayer, unless the 'restricted' option is set, in which case
  8715. * the 'restrictedExtent' option from the map is returned (if it
  8716. * is set).
  8717. */
  8718. getMaxExtent: function (options) {
  8719. var maxExtent = null;
  8720. if(options && options.restricted && this.restrictedExtent){
  8721. maxExtent = this.restrictedExtent;
  8722. } else if (this.baseLayer != null) {
  8723. maxExtent = this.baseLayer.maxExtent;
  8724. }
  8725. return maxExtent;
  8726. },
  8727. /**
  8728. * APIMethod: getNumZoomLevels
  8729. *
  8730. * Returns:
  8731. * {Integer} The total number of zoom levels that can be displayed by the
  8732. * current baseLayer.
  8733. */
  8734. getNumZoomLevels: function() {
  8735. var numZoomLevels = null;
  8736. if (this.baseLayer != null) {
  8737. numZoomLevels = this.baseLayer.numZoomLevels;
  8738. }
  8739. return numZoomLevels;
  8740. },
  8741. /********************************************************/
  8742. /* */
  8743. /* Baselayer Functions */
  8744. /* */
  8745. /* The following functions, all publicly exposed */
  8746. /* in the API?, are all merely wrappers to the */
  8747. /* the same calls on whatever layer is set as */
  8748. /* the current base layer */
  8749. /* */
  8750. /********************************************************/
  8751. /**
  8752. * APIMethod: getExtent
  8753. *
  8754. * Returns:
  8755. * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
  8756. * bounds of the current viewPort.
  8757. * If no baselayer is set, returns null.
  8758. */
  8759. getExtent: function () {
  8760. var extent = null;
  8761. if (this.baseLayer != null) {
  8762. extent = this.baseLayer.getExtent();
  8763. }
  8764. return extent;
  8765. },
  8766. /**
  8767. * APIMethod: getResolution
  8768. *
  8769. * Returns:
  8770. * {Float} The current resolution of the map.
  8771. * If no baselayer is set, returns null.
  8772. */
  8773. getResolution: function () {
  8774. var resolution = null;
  8775. if (this.baseLayer != null) {
  8776. resolution = this.baseLayer.getResolution();
  8777. } else if(this.allOverlays === true && this.layers.length > 0) {
  8778. // while adding the 1st layer to the map in allOverlays mode,
  8779. // this.baseLayer is not set yet when we need the resolution
  8780. // for calculateInRange.
  8781. resolution = this.layers[0].getResolution();
  8782. }
  8783. return resolution;
  8784. },
  8785. /**
  8786. * APIMethod: getUnits
  8787. *
  8788. * Returns:
  8789. * {Float} The current units of the map.
  8790. * If no baselayer is set, returns null.
  8791. */
  8792. getUnits: function () {
  8793. var units = null;
  8794. if (this.baseLayer != null) {
  8795. units = this.baseLayer.units;
  8796. }
  8797. return units;
  8798. },
  8799. /**
  8800. * APIMethod: getScale
  8801. *
  8802. * Returns:
  8803. * {Float} The current scale denominator of the map.
  8804. * If no baselayer is set, returns null.
  8805. */
  8806. getScale: function () {
  8807. var scale = null;
  8808. if (this.baseLayer != null) {
  8809. var res = this.getResolution();
  8810. var units = this.baseLayer.units;
  8811. scale = OpenLayers.Util.getScaleFromResolution(res, units);
  8812. }
  8813. return scale;
  8814. },
  8815. /**
  8816. * APIMethod: getZoomForExtent
  8817. *
  8818. * Parameters:
  8819. * bounds - {<OpenLayers.Bounds>}
  8820. * closest - {Boolean} Find the zoom level that most closely fits the
  8821. * specified bounds. Note that this may result in a zoom that does
  8822. * not exactly contain the entire extent.
  8823. * Default is false.
  8824. *
  8825. * Returns:
  8826. * {Integer} A suitable zoom level for the specified bounds.
  8827. * If no baselayer is set, returns null.
  8828. */
  8829. getZoomForExtent: function (bounds, closest) {
  8830. var zoom = null;
  8831. if (this.baseLayer != null) {
  8832. zoom = this.baseLayer.getZoomForExtent(bounds, closest);
  8833. }
  8834. return zoom;
  8835. },
  8836. /**
  8837. * APIMethod: getResolutionForZoom
  8838. *
  8839. * Parameters:
  8840. * zoom - {Float}
  8841. *
  8842. * Returns:
  8843. * {Float} A suitable resolution for the specified zoom. If no baselayer
  8844. * is set, returns null.
  8845. */
  8846. getResolutionForZoom: function(zoom) {
  8847. var resolution = null;
  8848. if(this.baseLayer) {
  8849. resolution = this.baseLayer.getResolutionForZoom(zoom);
  8850. }
  8851. return resolution;
  8852. },
  8853. /**
  8854. * APIMethod: getZoomForResolution
  8855. *
  8856. * Parameters:
  8857. * resolution - {Float}
  8858. * closest - {Boolean} Find the zoom level that corresponds to the absolute
  8859. * closest resolution, which may result in a zoom whose corresponding
  8860. * resolution is actually smaller than we would have desired (if this
  8861. * is being called from a getZoomForExtent() call, then this means that
  8862. * the returned zoom index might not actually contain the entire
  8863. * extent specified... but it'll be close).
  8864. * Default is false.
  8865. *
  8866. * Returns:
  8867. * {Integer} A suitable zoom level for the specified resolution.
  8868. * If no baselayer is set, returns null.
  8869. */
  8870. getZoomForResolution: function(resolution, closest) {
  8871. var zoom = null;
  8872. if (this.baseLayer != null) {
  8873. zoom = this.baseLayer.getZoomForResolution(resolution, closest);
  8874. }
  8875. return zoom;
  8876. },
  8877. /********************************************************/
  8878. /* */
  8879. /* Zooming Functions */
  8880. /* */
  8881. /* The following functions, all publicly exposed */
  8882. /* in the API, are all merely wrappers to the */
  8883. /* the setCenter() function */
  8884. /* */
  8885. /********************************************************/
  8886. /**
  8887. * APIMethod: zoomTo
  8888. * Zoom to a specific zoom level
  8889. *
  8890. * Parameters:
  8891. * zoom - {Integer}
  8892. */
  8893. zoomTo: function(zoom) {
  8894. if (this.isValidZoomLevel(zoom)) {
  8895. this.setCenter(null, zoom);
  8896. }
  8897. },
  8898. /**
  8899. * APIMethod: zoomIn
  8900. *
  8901. */
  8902. zoomIn: function() {
  8903. this.zoomTo(this.getZoom() + 1);
  8904. },
  8905. /**
  8906. * APIMethod: zoomOut
  8907. *
  8908. */
  8909. zoomOut: function() {
  8910. this.zoomTo(this.getZoom() - 1);
  8911. },
  8912. /**
  8913. * APIMethod: zoomToExtent
  8914. * Zoom to the passed in bounds, recenter
  8915. *
  8916. * Parameters:
  8917. * bounds - {<OpenLayers.Bounds>|Array} If provided as an array, the array
  8918. * should consist of four values (left, bottom, right, top).
  8919. * closest - {Boolean} Find the zoom level that most closely fits the
  8920. * specified bounds. Note that this may result in a zoom that does
  8921. * not exactly contain the entire extent.
  8922. * Default is false.
  8923. *
  8924. */
  8925. zoomToExtent: function(bounds, closest) {
  8926. if (!(bounds instanceof OpenLayers.Bounds)) {
  8927. bounds = new OpenLayers.Bounds(bounds);
  8928. }
  8929. var center = bounds.getCenterLonLat();
  8930. if (this.baseLayer.wrapDateLine) {
  8931. var maxExtent = this.getMaxExtent();
  8932. //fix straddling bounds (in the case of a bbox that straddles the
  8933. // dateline, it's left and right boundaries will appear backwards.
  8934. // we fix this by allowing a right value that is greater than the
  8935. // max value at the dateline -- this allows us to pass a valid
  8936. // bounds to calculate zoom)
  8937. //
  8938. bounds = bounds.clone();
  8939. while (bounds.right < bounds.left) {
  8940. bounds.right += maxExtent.getWidth();
  8941. }
  8942. //if the bounds was straddling (see above), then the center point
  8943. // we got from it was wrong. So we take our new bounds and ask it
  8944. // for the center.
  8945. //
  8946. center = bounds.getCenterLonLat().wrapDateLine(maxExtent);
  8947. }
  8948. this.setCenter(center, this.getZoomForExtent(bounds, closest));
  8949. },
  8950. /**
  8951. * APIMethod: zoomToMaxExtent
  8952. * Zoom to the full extent and recenter.
  8953. *
  8954. * Parameters:
  8955. * options - {Object}
  8956. *
  8957. * Allowed Options:
  8958. * restricted - {Boolean} True to zoom to restricted extent if it is
  8959. * set. Defaults to true.
  8960. */
  8961. zoomToMaxExtent: function(options) {
  8962. //restricted is true by default
  8963. var restricted = (options) ? options.restricted : true;
  8964. var maxExtent = this.getMaxExtent({
  8965. 'restricted': restricted
  8966. });
  8967. this.zoomToExtent(maxExtent);
  8968. },
  8969. /**
  8970. * APIMethod: zoomToScale
  8971. * Zoom to a specified scale
  8972. *
  8973. * Parameters:
  8974. * scale - {float}
  8975. * closest - {Boolean} Find the zoom level that most closely fits the
  8976. * specified scale. Note that this may result in a zoom that does
  8977. * not exactly contain the entire extent.
  8978. * Default is false.
  8979. *
  8980. */
  8981. zoomToScale: function(scale, closest) {
  8982. var res = OpenLayers.Util.getResolutionFromScale(scale,
  8983. this.baseLayer.units);
  8984. var halfWDeg = (this.size.w * res) / 2;
  8985. var halfHDeg = (this.size.h * res) / 2;
  8986. var center = this.getCachedCenter();
  8987. var extent = new OpenLayers.Bounds(center.lon - halfWDeg,
  8988. center.lat - halfHDeg,
  8989. center.lon + halfWDeg,
  8990. center.lat + halfHDeg);
  8991. this.zoomToExtent(extent, closest);
  8992. },
  8993. /********************************************************/
  8994. /* */
  8995. /* Translation Functions */
  8996. /* */
  8997. /* The following functions translate between */
  8998. /* LonLat, LayerPx, and ViewPortPx */
  8999. /* */
  9000. /********************************************************/
  9001. //
  9002. // TRANSLATION: LonLat <-> ViewPortPx
  9003. //
  9004. /**
  9005. * Method: getLonLatFromViewPortPx
  9006. *
  9007. * Parameters:
  9008. * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or
  9009. * an object with a 'x'
  9010. * and 'y' properties.
  9011. *
  9012. * Returns:
  9013. * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
  9014. * port <OpenLayers.Pixel>, translated into lon/lat
  9015. * by the current base layer.
  9016. */
  9017. getLonLatFromViewPortPx: function (viewPortPx) {
  9018. var lonlat = null;
  9019. if (this.baseLayer != null) {
  9020. lonlat = this.baseLayer.getLonLatFromViewPortPx(viewPortPx);
  9021. }
  9022. return lonlat;
  9023. },
  9024. /**
  9025. * APIMethod: getViewPortPxFromLonLat
  9026. *
  9027. * Parameters:
  9028. * lonlat - {<OpenLayers.LonLat>}
  9029. *
  9030. * Returns:
  9031. * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
  9032. * <OpenLayers.LonLat>, translated into view port
  9033. * pixels by the current base layer.
  9034. */
  9035. getViewPortPxFromLonLat: function (lonlat) {
  9036. var px = null;
  9037. if (this.baseLayer != null) {
  9038. px = this.baseLayer.getViewPortPxFromLonLat(lonlat);
  9039. }
  9040. return px;
  9041. },
  9042. //
  9043. // CONVENIENCE TRANSLATION FUNCTIONS FOR API
  9044. //
  9045. /**
  9046. * APIMethod: getLonLatFromPixel
  9047. *
  9048. * Parameters:
  9049. * px - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or an object with
  9050. * a 'x' and 'y' properties.
  9051. *
  9052. * Returns:
  9053. * {<OpenLayers.LonLat>} An OpenLayers.LonLat corresponding to the given
  9054. * OpenLayers.Pixel, translated into lon/lat by the
  9055. * current base layer
  9056. */
  9057. getLonLatFromPixel: function (px) {
  9058. return this.getLonLatFromViewPortPx(px);
  9059. },
  9060. /**
  9061. * APIMethod: getPixelFromLonLat
  9062. * Returns a pixel location given a map location. The map location is
  9063. * translated to an integer pixel location (in viewport pixel
  9064. * coordinates) by the current base layer.
  9065. *
  9066. * Parameters:
  9067. * lonlat - {<OpenLayers.LonLat>} A map location.
  9068. *
  9069. * Returns:
  9070. * {<OpenLayers.Pixel>} An OpenLayers.Pixel corresponding to the
  9071. * <OpenLayers.LonLat> translated into view port pixels by the current
  9072. * base layer.
  9073. */
  9074. getPixelFromLonLat: function (lonlat) {
  9075. var px = this.getViewPortPxFromLonLat(lonlat);
  9076. px.x = Math.round(px.x);
  9077. px.y = Math.round(px.y);
  9078. return px;
  9079. },
  9080. /**
  9081. * Method: getGeodesicPixelSize
  9082. *
  9083. * Parameters:
  9084. * px - {<OpenLayers.Pixel>} The pixel to get the geodesic length for. If
  9085. * not provided, the center pixel of the map viewport will be used.
  9086. *
  9087. * Returns:
  9088. * {<OpenLayers.Size>} The geodesic size of the pixel in kilometers.
  9089. */
  9090. getGeodesicPixelSize: function(px) {
  9091. var lonlat = px ? this.getLonLatFromPixel(px) : (
  9092. this.getCachedCenter() || new OpenLayers.LonLat(0, 0));
  9093. var res = this.getResolution();
  9094. var left = lonlat.add(-res / 2, 0);
  9095. var right = lonlat.add(res / 2, 0);
  9096. var bottom = lonlat.add(0, -res / 2);
  9097. var top = lonlat.add(0, res / 2);
  9098. var dest = new OpenLayers.Projection("EPSG:4326");
  9099. var source = this.getProjectionObject() || dest;
  9100. if(!source.equals(dest)) {
  9101. left.transform(source, dest);
  9102. right.transform(source, dest);
  9103. bottom.transform(source, dest);
  9104. top.transform(source, dest);
  9105. }
  9106. return new OpenLayers.Size(
  9107. OpenLayers.Util.distVincenty(left, right),
  9108. OpenLayers.Util.distVincenty(bottom, top)
  9109. );
  9110. },
  9111. //
  9112. // TRANSLATION: ViewPortPx <-> LayerPx
  9113. //
  9114. /**
  9115. * APIMethod: getViewPortPxFromLayerPx
  9116. *
  9117. * Parameters:
  9118. * layerPx - {<OpenLayers.Pixel>}
  9119. *
  9120. * Returns:
  9121. * {<OpenLayers.Pixel>} Layer Pixel translated into ViewPort Pixel
  9122. * coordinates
  9123. */
  9124. getViewPortPxFromLayerPx:function(layerPx) {
  9125. var viewPortPx = null;
  9126. if (layerPx != null) {
  9127. var dX = parseInt(this.layerContainerDiv.style.left);
  9128. var dY = parseInt(this.layerContainerDiv.style.top);
  9129. viewPortPx = layerPx.add(dX, dY);
  9130. }
  9131. return viewPortPx;
  9132. },
  9133. /**
  9134. * APIMethod: getLayerPxFromViewPortPx
  9135. *
  9136. * Parameters:
  9137. * viewPortPx - {<OpenLayers.Pixel>}
  9138. *
  9139. * Returns:
  9140. * {<OpenLayers.Pixel>} ViewPort Pixel translated into Layer Pixel
  9141. * coordinates
  9142. */
  9143. getLayerPxFromViewPortPx:function(viewPortPx) {
  9144. var layerPx = null;
  9145. if (viewPortPx != null) {
  9146. var dX = -parseInt(this.layerContainerDiv.style.left);
  9147. var dY = -parseInt(this.layerContainerDiv.style.top);
  9148. layerPx = viewPortPx.add(dX, dY);
  9149. if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
  9150. layerPx = null;
  9151. }
  9152. }
  9153. return layerPx;
  9154. },
  9155. //
  9156. // TRANSLATION: LonLat <-> LayerPx
  9157. //
  9158. /**
  9159. * Method: getLonLatFromLayerPx
  9160. *
  9161. * Parameters:
  9162. * px - {<OpenLayers.Pixel>}
  9163. *
  9164. * Returns:
  9165. * {<OpenLayers.LonLat>}
  9166. */
  9167. getLonLatFromLayerPx: function (px) {
  9168. //adjust for displacement of layerContainerDiv
  9169. px = this.getViewPortPxFromLayerPx(px);
  9170. return this.getLonLatFromViewPortPx(px);
  9171. },
  9172. /**
  9173. * APIMethod: getLayerPxFromLonLat
  9174. *
  9175. * Parameters:
  9176. * lonlat - {<OpenLayers.LonLat>} lonlat
  9177. *
  9178. * Returns:
  9179. * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
  9180. * <OpenLayers.LonLat>, translated into layer pixels
  9181. * by the current base layer
  9182. */
  9183. getLayerPxFromLonLat: function (lonlat) {
  9184. //adjust for displacement of layerContainerDiv
  9185. var px = this.getPixelFromLonLat(lonlat);
  9186. return this.getLayerPxFromViewPortPx(px);
  9187. },
  9188. CLASS_NAME: "OpenLayers.Map"
  9189. });
  9190. /**
  9191. * Constant: TILE_WIDTH
  9192. * {Integer} 256 Default tile width (unless otherwise specified)
  9193. */
  9194. OpenLayers.Map.TILE_WIDTH = 256;
  9195. /**
  9196. * Constant: TILE_HEIGHT
  9197. * {Integer} 256 Default tile height (unless otherwise specified)
  9198. */
  9199. OpenLayers.Map.TILE_HEIGHT = 256;
  9200. /* ======================================================================
  9201. OpenLayers/Layer.js
  9202. ====================================================================== */
  9203. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  9204. * full list of contributors). Published under the 2-clause BSD license.
  9205. * See license.txt in the OpenLayers distribution or repository for the
  9206. * full text of the license. */
  9207. /**
  9208. * @requires OpenLayers/BaseTypes/Class.js
  9209. * @requires OpenLayers/Map.js
  9210. * @requires OpenLayers/Projection.js
  9211. */
  9212. /**
  9213. * Class: OpenLayers.Layer
  9214. */
  9215. OpenLayers.Layer = OpenLayers.Class({
  9216. /**
  9217. * APIProperty: id
  9218. * {String}
  9219. */
  9220. id: null,
  9221. /**
  9222. * APIProperty: name
  9223. * {String}
  9224. */
  9225. name: null,
  9226. /**
  9227. * APIProperty: div
  9228. * {DOMElement}
  9229. */
  9230. div: null,
  9231. /**
  9232. * APIProperty: opacity
  9233. * {Float} The layer's opacity. Float number between 0.0 and 1.0. Default
  9234. * is 1.
  9235. */
  9236. opacity: 1,
  9237. /**
  9238. * APIProperty: alwaysInRange
  9239. * {Boolean} If a layer's display should not be scale-based, this should
  9240. * be set to true. This will cause the layer, as an overlay, to always
  9241. * be 'active', by always returning true from the calculateInRange()
  9242. * function.
  9243. *
  9244. * If not explicitly specified for a layer, its value will be
  9245. * determined on startup in initResolutions() based on whether or not
  9246. * any scale-specific properties have been set as options on the
  9247. * layer. If no scale-specific options have been set on the layer, we
  9248. * assume that it should always be in range.
  9249. *
  9250. * See #987 for more info.
  9251. */
  9252. alwaysInRange: null,
  9253. /**
  9254. * Constant: RESOLUTION_PROPERTIES
  9255. * {Array} The properties that are used for calculating resolutions
  9256. * information.
  9257. */
  9258. RESOLUTION_PROPERTIES: [
  9259. 'scales', 'resolutions',
  9260. 'maxScale', 'minScale',
  9261. 'maxResolution', 'minResolution',
  9262. 'numZoomLevels', 'maxZoomLevel'
  9263. ],
  9264. /**
  9265. * APIProperty: events
  9266. * {<OpenLayers.Events>}
  9267. *
  9268. * Register a listener for a particular event with the following syntax:
  9269. * (code)
  9270. * layer.events.register(type, obj, listener);
  9271. * (end)
  9272. *
  9273. * Listeners will be called with a reference to an event object. The
  9274. * properties of this event depends on exactly what happened.
  9275. *
  9276. * All event objects have at least the following properties:
  9277. * object - {Object} A reference to layer.events.object.
  9278. * element - {DOMElement} A reference to layer.events.element.
  9279. *
  9280. * Supported map event types:
  9281. * loadstart - Triggered when layer loading starts.
  9282. * loadend - Triggered when layer loading ends.
  9283. * visibilitychanged - Triggered when layer visibility is changed.
  9284. * move - Triggered when layer moves (triggered with every mousemove
  9285. * during a drag).
  9286. * moveend - Triggered when layer is done moving, object passed as
  9287. * argument has a zoomChanged boolean property which tells that the
  9288. * zoom has changed.
  9289. * added - Triggered after the layer is added to a map. Listeners will
  9290. * receive an object with a *map* property referencing the map and a
  9291. * *layer* property referencing the layer.
  9292. * removed - Triggered after the layer is removed from the map. Listeners
  9293. * will receive an object with a *map* property referencing the map and
  9294. * a *layer* property referencing the layer.
  9295. */
  9296. events: null,
  9297. /**
  9298. * APIProperty: map
  9299. * {<OpenLayers.Map>} This variable is set when the layer is added to
  9300. * the map, via the accessor function setMap().
  9301. */
  9302. map: null,
  9303. /**
  9304. * APIProperty: isBaseLayer
  9305. * {Boolean} Whether or not the layer is a base layer. This should be set
  9306. * individually by all subclasses. Default is false
  9307. */
  9308. isBaseLayer: false,
  9309. /**
  9310. * Property: alpha
  9311. * {Boolean} The layer's images have an alpha channel. Default is false.
  9312. */
  9313. alpha: false,
  9314. /**
  9315. * APIProperty: displayInLayerSwitcher
  9316. * {Boolean} Display the layer's name in the layer switcher. Default is
  9317. * true.
  9318. */
  9319. displayInLayerSwitcher: true,
  9320. /**
  9321. * APIProperty: visibility
  9322. * {Boolean} The layer should be displayed in the map. Default is true.
  9323. */
  9324. visibility: true,
  9325. /**
  9326. * APIProperty: attribution
  9327. * {String} Attribution string, displayed when an
  9328. * <OpenLayers.Control.Attribution> has been added to the map.
  9329. */
  9330. attribution: null,
  9331. /**
  9332. * Property: inRange
  9333. * {Boolean} The current map resolution is within the layer's min/max
  9334. * range. This is set in <OpenLayers.Map.setCenter> whenever the zoom
  9335. * changes.
  9336. */
  9337. inRange: false,
  9338. /**
  9339. * Propery: imageSize
  9340. * {<OpenLayers.Size>} For layers with a gutter, the image is larger than
  9341. * the tile by twice the gutter in each dimension.
  9342. */
  9343. imageSize: null,
  9344. // OPTIONS
  9345. /**
  9346. * Property: options
  9347. * {Object} An optional object whose properties will be set on the layer.
  9348. * Any of the layer properties can be set as a property of the options
  9349. * object and sent to the constructor when the layer is created.
  9350. */
  9351. options: null,
  9352. /**
  9353. * APIProperty: eventListeners
  9354. * {Object} If set as an option at construction, the eventListeners
  9355. * object will be registered with <OpenLayers.Events.on>. Object
  9356. * structure must be a listeners object as shown in the example for
  9357. * the events.on method.
  9358. */
  9359. eventListeners: null,
  9360. /**
  9361. * APIProperty: gutter
  9362. * {Integer} Determines the width (in pixels) of the gutter around image
  9363. * tiles to ignore. By setting this property to a non-zero value,
  9364. * images will be requested that are wider and taller than the tile
  9365. * size by a value of 2 x gutter. This allows artifacts of rendering
  9366. * at tile edges to be ignored. Set a gutter value that is equal to
  9367. * half the size of the widest symbol that needs to be displayed.
  9368. * Defaults to zero. Non-tiled layers always have zero gutter.
  9369. */
  9370. gutter: 0,
  9371. /**
  9372. * APIProperty: projection
  9373. * {<OpenLayers.Projection>} or {<String>} Specifies the projection of the layer.
  9374. * Can be set in the layer options. If not specified in the layer options,
  9375. * it is set to the default projection specified in the map,
  9376. * when the layer is added to the map.
  9377. * Projection along with default maxExtent and resolutions
  9378. * are set automatically with commercial baselayers in EPSG:3857,
  9379. * such as Google, Bing and OpenStreetMap, and do not need to be specified.
  9380. * Otherwise, if specifying projection, also set maxExtent,
  9381. * maxResolution or resolutions as appropriate.
  9382. * When using vector layers with strategies, layer projection should be set
  9383. * to the projection of the source data if that is different from the map default.
  9384. *
  9385. * Can be either a string or an <OpenLayers.Projection> object;
  9386. * if a string is passed, will be converted to an object when
  9387. * the layer is added to the map.
  9388. *
  9389. */
  9390. projection: null,
  9391. /**
  9392. * APIProperty: units
  9393. * {String} The layer map units. Defaults to null. Possible values
  9394. * are 'degrees' (or 'dd'), 'm', 'ft', 'km', 'mi', 'inches'.
  9395. * Normally taken from the projection.
  9396. * Only required if both map and layers do not define a projection,
  9397. * or if they define a projection which does not define units.
  9398. */
  9399. units: null,
  9400. /**
  9401. * APIProperty: scales
  9402. * {Array} An array of map scales in descending order. The values in the
  9403. * array correspond to the map scale denominator. Note that these
  9404. * values only make sense if the display (monitor) resolution of the
  9405. * client is correctly guessed by whomever is configuring the
  9406. * application. In addition, the units property must also be set.
  9407. * Use <resolutions> instead wherever possible.
  9408. */
  9409. scales: null,
  9410. /**
  9411. * APIProperty: resolutions
  9412. * {Array} A list of map resolutions (map units per pixel) in descending
  9413. * order. If this is not set in the layer constructor, it will be set
  9414. * based on other resolution related properties (maxExtent,
  9415. * maxResolution, maxScale, etc.).
  9416. */
  9417. resolutions: null,
  9418. /**
  9419. * APIProperty: maxExtent
  9420. * {<OpenLayers.Bounds>|Array} If provided as an array, the array
  9421. * should consist of four values (left, bottom, right, top).
  9422. * The maximum extent for the layer. Defaults to null.
  9423. *
  9424. * The center of these bounds will not stray outside
  9425. * of the viewport extent during panning. In addition, if
  9426. * <displayOutsideMaxExtent> is set to false, data will not be
  9427. * requested that falls completely outside of these bounds.
  9428. */
  9429. maxExtent: null,
  9430. /**
  9431. * APIProperty: minExtent
  9432. * {<OpenLayers.Bounds>|Array} If provided as an array, the array
  9433. * should consist of four values (left, bottom, right, top).
  9434. * The minimum extent for the layer. Defaults to null.
  9435. */
  9436. minExtent: null,
  9437. /**
  9438. * APIProperty: maxResolution
  9439. * {Float} Default max is 360 deg / 256 px, which corresponds to
  9440. * zoom level 0 on gmaps. Specify a different value in the layer
  9441. * options if you are not using the default <OpenLayers.Map.tileSize>
  9442. * and displaying the whole world.
  9443. */
  9444. maxResolution: null,
  9445. /**
  9446. * APIProperty: minResolution
  9447. * {Float}
  9448. */
  9449. minResolution: null,
  9450. /**
  9451. * APIProperty: numZoomLevels
  9452. * {Integer}
  9453. */
  9454. numZoomLevels: null,
  9455. /**
  9456. * APIProperty: minScale
  9457. * {Float}
  9458. */
  9459. minScale: null,
  9460. /**
  9461. * APIProperty: maxScale
  9462. * {Float}
  9463. */
  9464. maxScale: null,
  9465. /**
  9466. * APIProperty: displayOutsideMaxExtent
  9467. * {Boolean} Request map tiles that are completely outside of the max
  9468. * extent for this layer. Defaults to false.
  9469. */
  9470. displayOutsideMaxExtent: false,
  9471. /**
  9472. * APIProperty: wrapDateLine
  9473. * {Boolean} Wraps the world at the international dateline, so the map can
  9474. * be panned infinitely in longitudinal direction. Only use this on the
  9475. * base layer, and only if the layer's maxExtent equals the world bounds.
  9476. * #487 for more info.
  9477. */
  9478. wrapDateLine: false,
  9479. /**
  9480. * Property: metadata
  9481. * {Object} This object can be used to store additional information on a
  9482. * layer object.
  9483. */
  9484. metadata: null,
  9485. /**
  9486. * Constructor: OpenLayers.Layer
  9487. *
  9488. * Parameters:
  9489. * name - {String} The layer name
  9490. * options - {Object} Hashtable of extra options to tag onto the layer
  9491. */
  9492. initialize: function(name, options) {
  9493. this.metadata = {};
  9494. this.addOptions(options);
  9495. this.name = name;
  9496. if (this.id == null) {
  9497. this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
  9498. this.div = OpenLayers.Util.createDiv(this.id);
  9499. this.div.style.width = "100%";
  9500. this.div.style.height = "100%";
  9501. this.div.dir = "ltr";
  9502. this.events = new OpenLayers.Events(this, this.div);
  9503. if(this.eventListeners instanceof Object) {
  9504. this.events.on(this.eventListeners);
  9505. }
  9506. }
  9507. },
  9508. /**
  9509. * Method: destroy
  9510. * Destroy is a destructor: this is to alleviate cyclic references which
  9511. * the Javascript garbage cleaner can not take care of on its own.
  9512. *
  9513. * Parameters:
  9514. * setNewBaseLayer - {Boolean} Set a new base layer when this layer has
  9515. * been destroyed. Default is true.
  9516. */
  9517. destroy: function(setNewBaseLayer) {
  9518. if (setNewBaseLayer == null) {
  9519. setNewBaseLayer = true;
  9520. }
  9521. if (this.map != null) {
  9522. this.map.removeLayer(this, setNewBaseLayer);
  9523. }
  9524. this.projection = null;
  9525. this.map = null;
  9526. this.name = null;
  9527. this.div = null;
  9528. this.options = null;
  9529. if (this.events) {
  9530. if(this.eventListeners) {
  9531. this.events.un(this.eventListeners);
  9532. }
  9533. this.events.destroy();
  9534. }
  9535. this.eventListeners = null;
  9536. this.events = null;
  9537. },
  9538. /**
  9539. * Method: clone
  9540. *
  9541. * Parameters:
  9542. * obj - {<OpenLayers.Layer>} The layer to be cloned
  9543. *
  9544. * Returns:
  9545. * {<OpenLayers.Layer>} An exact clone of this <OpenLayers.Layer>
  9546. */
  9547. clone: function (obj) {
  9548. if (obj == null) {
  9549. obj = new OpenLayers.Layer(this.name, this.getOptions());
  9550. }
  9551. // catch any randomly tagged-on properties
  9552. OpenLayers.Util.applyDefaults(obj, this);
  9553. // a cloned layer should never have its map property set
  9554. // because it has not been added to a map yet.
  9555. obj.map = null;
  9556. return obj;
  9557. },
  9558. /**
  9559. * Method: getOptions
  9560. * Extracts an object from the layer with the properties that were set as
  9561. * options, but updates them with the values currently set on the
  9562. * instance.
  9563. *
  9564. * Returns:
  9565. * {Object} the <options> of the layer, representing the current state.
  9566. */
  9567. getOptions: function() {
  9568. var options = {};
  9569. for(var o in this.options) {
  9570. options[o] = this[o];
  9571. }
  9572. return options;
  9573. },
  9574. /**
  9575. * APIMethod: setName
  9576. * Sets the new layer name for this layer. Can trigger a changelayer event
  9577. * on the map.
  9578. *
  9579. * Parameters:
  9580. * newName - {String} The new name.
  9581. */
  9582. setName: function(newName) {
  9583. if (newName != this.name) {
  9584. this.name = newName;
  9585. if (this.map != null) {
  9586. this.map.events.triggerEvent("changelayer", {
  9587. layer: this,
  9588. property: "name"
  9589. });
  9590. }
  9591. }
  9592. },
  9593. /**
  9594. * APIMethod: addOptions
  9595. *
  9596. * Parameters:
  9597. * newOptions - {Object}
  9598. * reinitialize - {Boolean} If set to true, and if resolution options of the
  9599. * current baseLayer were changed, the map will be recentered to make
  9600. * sure that it is displayed with a valid resolution, and a
  9601. * changebaselayer event will be triggered.
  9602. */
  9603. addOptions: function (newOptions, reinitialize) {
  9604. if (this.options == null) {
  9605. this.options = {};
  9606. }
  9607. if (newOptions) {
  9608. // make sure this.projection references a projection object
  9609. if(typeof newOptions.projection == "string") {
  9610. newOptions.projection = new OpenLayers.Projection(newOptions.projection);
  9611. }
  9612. if (newOptions.projection) {
  9613. // get maxResolution, units and maxExtent from projection defaults if
  9614. // they are not defined already
  9615. OpenLayers.Util.applyDefaults(newOptions,
  9616. OpenLayers.Projection.defaults[newOptions.projection.getCode()]);
  9617. }
  9618. // allow array for extents
  9619. if (newOptions.maxExtent && !(newOptions.maxExtent instanceof OpenLayers.Bounds)) {
  9620. newOptions.maxExtent = new OpenLayers.Bounds(newOptions.maxExtent);
  9621. }
  9622. if (newOptions.minExtent && !(newOptions.minExtent instanceof OpenLayers.Bounds)) {
  9623. newOptions.minExtent = new OpenLayers.Bounds(newOptions.minExtent);
  9624. }
  9625. }
  9626. // update our copy for clone
  9627. OpenLayers.Util.extend(this.options, newOptions);
  9628. // add new options to this
  9629. OpenLayers.Util.extend(this, newOptions);
  9630. // get the units from the projection, if we have a projection
  9631. // and it it has units
  9632. if(this.projection && this.projection.getUnits()) {
  9633. this.units = this.projection.getUnits();
  9634. }
  9635. // re-initialize resolutions if necessary, i.e. if any of the
  9636. // properties of the "properties" array defined below is set
  9637. // in the new options
  9638. if(this.map) {
  9639. // store current resolution so we can try to restore it later
  9640. var resolution = this.map.getResolution();
  9641. var properties = this.RESOLUTION_PROPERTIES.concat(
  9642. ["projection", "units", "minExtent", "maxExtent"]
  9643. );
  9644. for(var o in newOptions) {
  9645. if(newOptions.hasOwnProperty(o) &&
  9646. OpenLayers.Util.indexOf(properties, o) >= 0) {
  9647. this.initResolutions();
  9648. if (reinitialize && this.map.baseLayer === this) {
  9649. // update map position, and restore previous resolution
  9650. this.map.setCenter(this.map.getCenter(),
  9651. this.map.getZoomForResolution(resolution),
  9652. false, true
  9653. );
  9654. // trigger a changebaselayer event to make sure that
  9655. // all controls (especially
  9656. // OpenLayers.Control.PanZoomBar) get notified of the
  9657. // new options
  9658. this.map.events.triggerEvent("changebaselayer", {
  9659. layer: this
  9660. });
  9661. }
  9662. break;
  9663. }
  9664. }
  9665. }
  9666. },
  9667. /**
  9668. * APIMethod: onMapResize
  9669. * This function can be implemented by subclasses
  9670. */
  9671. onMapResize: function() {
  9672. //this function can be implemented by subclasses
  9673. },
  9674. /**
  9675. * APIMethod: redraw
  9676. * Redraws the layer. Returns true if the layer was redrawn, false if not.
  9677. *
  9678. * Returns:
  9679. * {Boolean} The layer was redrawn.
  9680. */
  9681. redraw: function() {
  9682. var redrawn = false;
  9683. if (this.map) {
  9684. // min/max Range may have changed
  9685. this.inRange = this.calculateInRange();
  9686. // map's center might not yet be set
  9687. var extent = this.getExtent();
  9688. if (extent && this.inRange && this.visibility) {
  9689. var zoomChanged = true;
  9690. this.moveTo(extent, zoomChanged, false);
  9691. this.events.triggerEvent("moveend",
  9692. {"zoomChanged": zoomChanged});
  9693. redrawn = true;
  9694. }
  9695. }
  9696. return redrawn;
  9697. },
  9698. /**
  9699. * Method: moveTo
  9700. *
  9701. * Parameters:
  9702. * bounds - {<OpenLayers.Bounds>}
  9703. * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
  9704. * do some init work in that case.
  9705. * dragging - {Boolean}
  9706. */
  9707. moveTo:function(bounds, zoomChanged, dragging) {
  9708. var display = this.visibility;
  9709. if (!this.isBaseLayer) {
  9710. display = display && this.inRange;
  9711. }
  9712. this.display(display);
  9713. },
  9714. /**
  9715. * Method: moveByPx
  9716. * Move the layer based on pixel vector. To be implemented by subclasses.
  9717. *
  9718. * Parameters:
  9719. * dx - {Number} The x coord of the displacement vector.
  9720. * dy - {Number} The y coord of the displacement vector.
  9721. */
  9722. moveByPx: function(dx, dy) {
  9723. },
  9724. /**
  9725. * Method: setMap
  9726. * Set the map property for the layer. This is done through an accessor
  9727. * so that subclasses can override this and take special action once
  9728. * they have their map variable set.
  9729. *
  9730. * Here we take care to bring over any of the necessary default
  9731. * properties from the map.
  9732. *
  9733. * Parameters:
  9734. * map - {<OpenLayers.Map>}
  9735. */
  9736. setMap: function(map) {
  9737. if (this.map == null) {
  9738. this.map = map;
  9739. // grab some essential layer data from the map if it hasn't already
  9740. // been set
  9741. this.maxExtent = this.maxExtent || this.map.maxExtent;
  9742. this.minExtent = this.minExtent || this.map.minExtent;
  9743. this.projection = this.projection || this.map.projection;
  9744. if (typeof this.projection == "string") {
  9745. this.projection = new OpenLayers.Projection(this.projection);
  9746. }
  9747. // Check the projection to see if we can get units -- if not, refer
  9748. // to properties.
  9749. this.units = this.projection.getUnits() ||
  9750. this.units || this.map.units;
  9751. this.initResolutions();
  9752. if (!this.isBaseLayer) {
  9753. this.inRange = this.calculateInRange();
  9754. var show = ((this.visibility) && (this.inRange));
  9755. this.div.style.display = show ? "" : "none";
  9756. }
  9757. // deal with gutters
  9758. this.setTileSize();
  9759. }
  9760. },
  9761. /**
  9762. * Method: afterAdd
  9763. * Called at the end of the map.addLayer sequence. At this point, the map
  9764. * will have a base layer. To be overridden by subclasses.
  9765. */
  9766. afterAdd: function() {
  9767. },
  9768. /**
  9769. * APIMethod: removeMap
  9770. * Just as setMap() allows each layer the possibility to take a
  9771. * personalized action on being added to the map, removeMap() allows
  9772. * each layer to take a personalized action on being removed from it.
  9773. * For now, this will be mostly unused, except for the EventPane layer,
  9774. * which needs this hook so that it can remove the special invisible
  9775. * pane.
  9776. *
  9777. * Parameters:
  9778. * map - {<OpenLayers.Map>}
  9779. */
  9780. removeMap: function(map) {
  9781. //to be overridden by subclasses
  9782. },
  9783. /**
  9784. * APIMethod: getImageSize
  9785. *
  9786. * Parameters:
  9787. * bounds - {<OpenLayers.Bounds>} optional tile bounds, can be used
  9788. * by subclasses that have to deal with different tile sizes at the
  9789. * layer extent edges (e.g. Zoomify)
  9790. *
  9791. * Returns:
  9792. * {<OpenLayers.Size>} The size that the image should be, taking into
  9793. * account gutters.
  9794. */
  9795. getImageSize: function(bounds) {
  9796. return (this.imageSize || this.tileSize);
  9797. },
  9798. /**
  9799. * APIMethod: setTileSize
  9800. * Set the tile size based on the map size. This also sets layer.imageSize
  9801. * or use by Tile.Image.
  9802. *
  9803. * Parameters:
  9804. * size - {<OpenLayers.Size>}
  9805. */
  9806. setTileSize: function(size) {
  9807. var tileSize = (size) ? size :
  9808. ((this.tileSize) ? this.tileSize :
  9809. this.map.getTileSize());
  9810. this.tileSize = tileSize;
  9811. if(this.gutter) {
  9812. // layers with gutters need non-null tile sizes
  9813. //if(tileSize == null) {
  9814. // OpenLayers.console.error("Error in layer.setMap() for " +
  9815. // this.name + ": layers with " +
  9816. // "gutters need non-null tile sizes");
  9817. //}
  9818. this.imageSize = new OpenLayers.Size(tileSize.w + (2*this.gutter),
  9819. tileSize.h + (2*this.gutter));
  9820. }
  9821. },
  9822. /**
  9823. * APIMethod: getVisibility
  9824. *
  9825. * Returns:
  9826. * {Boolean} The layer should be displayed (if in range).
  9827. */
  9828. getVisibility: function() {
  9829. return this.visibility;
  9830. },
  9831. /**
  9832. * APIMethod: setVisibility
  9833. * Set the visibility flag for the layer and hide/show & redraw
  9834. * accordingly. Fire event unless otherwise specified
  9835. *
  9836. * Note that visibility is no longer simply whether or not the layer's
  9837. * style.display is set to "block". Now we store a 'visibility' state
  9838. * property on the layer class, this allows us to remember whether or
  9839. * not we *desire* for a layer to be visible. In the case where the
  9840. * map's resolution is out of the layer's range, this desire may be
  9841. * subverted.
  9842. *
  9843. * Parameters:
  9844. * visibility - {Boolean} Whether or not to display the layer (if in range)
  9845. */
  9846. setVisibility: function(visibility) {
  9847. if (visibility != this.visibility) {
  9848. this.visibility = visibility;
  9849. this.display(visibility);
  9850. this.redraw();
  9851. if (this.map != null) {
  9852. this.map.events.triggerEvent("changelayer", {
  9853. layer: this,
  9854. property: "visibility"
  9855. });
  9856. }
  9857. this.events.triggerEvent("visibilitychanged");
  9858. }
  9859. },
  9860. /**
  9861. * APIMethod: display
  9862. * Hide or show the Layer. This is designed to be used internally, and
  9863. * is not generally the way to enable or disable the layer. For that,
  9864. * use the setVisibility function instead..
  9865. *
  9866. * Parameters:
  9867. * display - {Boolean}
  9868. */
  9869. display: function(display) {
  9870. if (display != (this.div.style.display != "none")) {
  9871. this.div.style.display = (display && this.calculateInRange()) ? "block" : "none";
  9872. }
  9873. },
  9874. /**
  9875. * APIMethod: calculateInRange
  9876. *
  9877. * Returns:
  9878. * {Boolean} The layer is displayable at the current map's current
  9879. * resolution. Note that if 'alwaysInRange' is true for the layer,
  9880. * this function will always return true.
  9881. */
  9882. calculateInRange: function() {
  9883. var inRange = false;
  9884. if (this.alwaysInRange) {
  9885. inRange = true;
  9886. } else {
  9887. if (this.map) {
  9888. var resolution = this.map.getResolution();
  9889. inRange = ( (resolution >= this.minResolution) &&
  9890. (resolution <= this.maxResolution) );
  9891. }
  9892. }
  9893. return inRange;
  9894. },
  9895. /**
  9896. * APIMethod: setIsBaseLayer
  9897. *
  9898. * Parameters:
  9899. * isBaseLayer - {Boolean}
  9900. */
  9901. setIsBaseLayer: function(isBaseLayer) {
  9902. if (isBaseLayer != this.isBaseLayer) {
  9903. this.isBaseLayer = isBaseLayer;
  9904. if (this.map != null) {
  9905. this.map.events.triggerEvent("changebaselayer", {
  9906. layer: this
  9907. });
  9908. }
  9909. }
  9910. },
  9911. /********************************************************/
  9912. /* */
  9913. /* Baselayer Functions */
  9914. /* */
  9915. /********************************************************/
  9916. /**
  9917. * Method: initResolutions
  9918. * This method's responsibility is to set up the 'resolutions' array
  9919. * for the layer -- this array is what the layer will use to interface
  9920. * between the zoom levels of the map and the resolution display
  9921. * of the layer.
  9922. *
  9923. * The user has several options that determine how the array is set up.
  9924. *
  9925. * For a detailed explanation, see the following wiki from the
  9926. * openlayers.org homepage:
  9927. * http://trac.openlayers.org/wiki/SettingZoomLevels
  9928. */
  9929. initResolutions: function() {
  9930. // ok we want resolutions, here's our strategy:
  9931. //
  9932. // 1. if resolutions are defined in the layer config, use them
  9933. // 2. else, if scales are defined in the layer config then derive
  9934. // resolutions from these scales
  9935. // 3. else, attempt to calculate resolutions from maxResolution,
  9936. // minResolution, numZoomLevels, maxZoomLevel set in the
  9937. // layer config
  9938. // 4. if we still don't have resolutions, and if resolutions
  9939. // are defined in the same, use them
  9940. // 5. else, if scales are defined in the map then derive
  9941. // resolutions from these scales
  9942. // 6. else, attempt to calculate resolutions from maxResolution,
  9943. // minResolution, numZoomLevels, maxZoomLevel set in the
  9944. // map
  9945. // 7. hope for the best!
  9946. var i, len, p;
  9947. var props = {}, alwaysInRange = true;
  9948. // get resolution data from layer config
  9949. // (we also set alwaysInRange in the layer as appropriate)
  9950. for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
  9951. p = this.RESOLUTION_PROPERTIES[i];
  9952. props[p] = this.options[p];
  9953. if(alwaysInRange && this.options[p]) {
  9954. alwaysInRange = false;
  9955. }
  9956. }
  9957. if(this.alwaysInRange == null) {
  9958. this.alwaysInRange = alwaysInRange;
  9959. }
  9960. // if we don't have resolutions then attempt to derive them from scales
  9961. if(props.resolutions == null) {
  9962. props.resolutions = this.resolutionsFromScales(props.scales);
  9963. }
  9964. // if we still don't have resolutions then attempt to calculate them
  9965. if(props.resolutions == null) {
  9966. props.resolutions = this.calculateResolutions(props);
  9967. }
  9968. // if we couldn't calculate resolutions then we look at we have
  9969. // in the map
  9970. if(props.resolutions == null) {
  9971. for(i=0, len=this.RESOLUTION_PROPERTIES.length; i<len; i++) {
  9972. p = this.RESOLUTION_PROPERTIES[i];
  9973. props[p] = this.options[p] != null ?
  9974. this.options[p] : this.map[p];
  9975. }
  9976. if(props.resolutions == null) {
  9977. props.resolutions = this.resolutionsFromScales(props.scales);
  9978. }
  9979. if(props.resolutions == null) {
  9980. props.resolutions = this.calculateResolutions(props);
  9981. }
  9982. }
  9983. // ok, we new need to set properties in the instance
  9984. // get maxResolution from the config if it's defined there
  9985. var maxResolution;
  9986. if(this.options.maxResolution &&
  9987. this.options.maxResolution !== "auto") {
  9988. maxResolution = this.options.maxResolution;
  9989. }
  9990. if(this.options.minScale) {
  9991. maxResolution = OpenLayers.Util.getResolutionFromScale(
  9992. this.options.minScale, this.units);
  9993. }
  9994. // get minResolution from the config if it's defined there
  9995. var minResolution;
  9996. if(this.options.minResolution &&
  9997. this.options.minResolution !== "auto") {
  9998. minResolution = this.options.minResolution;
  9999. }
  10000. if(this.options.maxScale) {
  10001. minResolution = OpenLayers.Util.getResolutionFromScale(
  10002. this.options.maxScale, this.units);
  10003. }
  10004. if(props.resolutions) {
  10005. //sort resolutions array descendingly
  10006. props.resolutions.sort(function(a, b) {
  10007. return (b - a);
  10008. });
  10009. // if we still don't have a maxResolution get it from the
  10010. // resolutions array
  10011. if(!maxResolution) {
  10012. maxResolution = props.resolutions[0];
  10013. }
  10014. // if we still don't have a minResolution get it from the
  10015. // resolutions array
  10016. if(!minResolution) {
  10017. var lastIdx = props.resolutions.length - 1;
  10018. minResolution = props.resolutions[lastIdx];
  10019. }
  10020. }
  10021. this.resolutions = props.resolutions;
  10022. if(this.resolutions) {
  10023. len = this.resolutions.length;
  10024. this.scales = new Array(len);
  10025. for(i=0; i<len; i++) {
  10026. this.scales[i] = OpenLayers.Util.getScaleFromResolution(
  10027. this.resolutions[i], this.units);
  10028. }
  10029. this.numZoomLevels = len;
  10030. }
  10031. this.minResolution = minResolution;
  10032. if(minResolution) {
  10033. this.maxScale = OpenLayers.Util.getScaleFromResolution(
  10034. minResolution, this.units);
  10035. }
  10036. this.maxResolution = maxResolution;
  10037. if(maxResolution) {
  10038. this.minScale = OpenLayers.Util.getScaleFromResolution(
  10039. maxResolution, this.units);
  10040. }
  10041. },
  10042. /**
  10043. * Method: resolutionsFromScales
  10044. * Derive resolutions from scales.
  10045. *
  10046. * Parameters:
  10047. * scales - {Array(Number)} Scales
  10048. *
  10049. * Returns
  10050. * {Array(Number)} Resolutions
  10051. */
  10052. resolutionsFromScales: function(scales) {
  10053. if(scales == null) {
  10054. return;
  10055. }
  10056. var resolutions, i, len;
  10057. len = scales.length;
  10058. resolutions = new Array(len);
  10059. for(i=0; i<len; i++) {
  10060. resolutions[i] = OpenLayers.Util.getResolutionFromScale(
  10061. scales[i], this.units);
  10062. }
  10063. return resolutions;
  10064. },
  10065. /**
  10066. * Method: calculateResolutions
  10067. * Calculate resolutions based on the provided properties.
  10068. *
  10069. * Parameters:
  10070. * props - {Object} Properties
  10071. *
  10072. * Returns:
  10073. * {Array({Number})} Array of resolutions.
  10074. */
  10075. calculateResolutions: function(props) {
  10076. var viewSize, wRes, hRes;
  10077. // determine maxResolution
  10078. var maxResolution = props.maxResolution;
  10079. if(props.minScale != null) {
  10080. maxResolution =
  10081. OpenLayers.Util.getResolutionFromScale(props.minScale,
  10082. this.units);
  10083. } else if(maxResolution == "auto" && this.maxExtent != null) {
  10084. viewSize = this.map.getSize();
  10085. wRes = this.maxExtent.getWidth() / viewSize.w;
  10086. hRes = this.maxExtent.getHeight() / viewSize.h;
  10087. maxResolution = Math.max(wRes, hRes);
  10088. }
  10089. // determine minResolution
  10090. var minResolution = props.minResolution;
  10091. if(props.maxScale != null) {
  10092. minResolution =
  10093. OpenLayers.Util.getResolutionFromScale(props.maxScale,
  10094. this.units);
  10095. } else if(props.minResolution == "auto" && this.minExtent != null) {
  10096. viewSize = this.map.getSize();
  10097. wRes = this.minExtent.getWidth() / viewSize.w;
  10098. hRes = this.minExtent.getHeight()/ viewSize.h;
  10099. minResolution = Math.max(wRes, hRes);
  10100. }
  10101. if(typeof maxResolution !== "number" &&
  10102. typeof minResolution !== "number" &&
  10103. this.maxExtent != null) {
  10104. // maxResolution for default grid sets assumes that at zoom
  10105. // level zero, the whole world fits on one tile.
  10106. var tileSize = this.map.getTileSize();
  10107. maxResolution = Math.max(
  10108. this.maxExtent.getWidth() / tileSize.w,
  10109. this.maxExtent.getHeight() / tileSize.h
  10110. );
  10111. }
  10112. // determine numZoomLevels
  10113. var maxZoomLevel = props.maxZoomLevel;
  10114. var numZoomLevels = props.numZoomLevels;
  10115. if(typeof minResolution === "number" &&
  10116. typeof maxResolution === "number" && numZoomLevels === undefined) {
  10117. var ratio = maxResolution / minResolution;
  10118. numZoomLevels = Math.floor(Math.log(ratio) / Math.log(2)) + 1;
  10119. } else if(numZoomLevels === undefined && maxZoomLevel != null) {
  10120. numZoomLevels = maxZoomLevel + 1;
  10121. }
  10122. // are we able to calculate resolutions?
  10123. if(typeof numZoomLevels !== "number" || numZoomLevels <= 0 ||
  10124. (typeof maxResolution !== "number" &&
  10125. typeof minResolution !== "number")) {
  10126. return;
  10127. }
  10128. // now we have numZoomLevels and at least one of maxResolution
  10129. // or minResolution, we can populate the resolutions array
  10130. var resolutions = new Array(numZoomLevels);
  10131. var base = 2;
  10132. if(typeof minResolution == "number" &&
  10133. typeof maxResolution == "number") {
  10134. // if maxResolution and minResolution are set, we calculate
  10135. // the base for exponential scaling that starts at
  10136. // maxResolution and ends at minResolution in numZoomLevels
  10137. // steps.
  10138. base = Math.pow(
  10139. (maxResolution / minResolution),
  10140. (1 / (numZoomLevels - 1))
  10141. );
  10142. }
  10143. var i;
  10144. if(typeof maxResolution === "number") {
  10145. for(i=0; i<numZoomLevels; i++) {
  10146. resolutions[i] = maxResolution / Math.pow(base, i);
  10147. }
  10148. } else {
  10149. for(i=0; i<numZoomLevels; i++) {
  10150. resolutions[numZoomLevels - 1 - i] =
  10151. minResolution * Math.pow(base, i);
  10152. }
  10153. }
  10154. return resolutions;
  10155. },
  10156. /**
  10157. * APIMethod: getResolution
  10158. *
  10159. * Returns:
  10160. * {Float} The currently selected resolution of the map, taken from the
  10161. * resolutions array, indexed by current zoom level.
  10162. */
  10163. getResolution: function() {
  10164. var zoom = this.map.getZoom();
  10165. return this.getResolutionForZoom(zoom);
  10166. },
  10167. /**
  10168. * APIMethod: getExtent
  10169. *
  10170. * Returns:
  10171. * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
  10172. * bounds of the current viewPort.
  10173. */
  10174. getExtent: function() {
  10175. // just use stock map calculateBounds function -- passing no arguments
  10176. // means it will user map's current center & resolution
  10177. //
  10178. return this.map.calculateBounds();
  10179. },
  10180. /**
  10181. * APIMethod: getZoomForExtent
  10182. *
  10183. * Parameters:
  10184. * extent - {<OpenLayers.Bounds>}
  10185. * closest - {Boolean} Find the zoom level that most closely fits the
  10186. * specified bounds. Note that this may result in a zoom that does
  10187. * not exactly contain the entire extent.
  10188. * Default is false.
  10189. *
  10190. * Returns:
  10191. * {Integer} The index of the zoomLevel (entry in the resolutions array)
  10192. * for the passed-in extent. We do this by calculating the ideal
  10193. * resolution for the given extent (based on the map size) and then
  10194. * calling getZoomForResolution(), passing along the 'closest'
  10195. * parameter.
  10196. */
  10197. getZoomForExtent: function(extent, closest) {
  10198. var viewSize = this.map.getSize();
  10199. var idealResolution = Math.max( extent.getWidth() / viewSize.w,
  10200. extent.getHeight() / viewSize.h );
  10201. return this.getZoomForResolution(idealResolution, closest);
  10202. },
  10203. /**
  10204. * Method: getDataExtent
  10205. * Calculates the max extent which includes all of the data for the layer.
  10206. * This function is to be implemented by subclasses.
  10207. *
  10208. * Returns:
  10209. * {<OpenLayers.Bounds>}
  10210. */
  10211. getDataExtent: function () {
  10212. //to be implemented by subclasses
  10213. },
  10214. /**
  10215. * APIMethod: getResolutionForZoom
  10216. *
  10217. * Parameters:
  10218. * zoom - {Float}
  10219. *
  10220. * Returns:
  10221. * {Float} A suitable resolution for the specified zoom.
  10222. */
  10223. getResolutionForZoom: function(zoom) {
  10224. zoom = Math.max(0, Math.min(zoom, this.resolutions.length - 1));
  10225. var resolution;
  10226. if(this.map.fractionalZoom) {
  10227. var low = Math.floor(zoom);
  10228. var high = Math.ceil(zoom);
  10229. resolution = this.resolutions[low] -
  10230. ((zoom-low) * (this.resolutions[low]-this.resolutions[high]));
  10231. } else {
  10232. resolution = this.resolutions[Math.round(zoom)];
  10233. }
  10234. return resolution;
  10235. },
  10236. /**
  10237. * APIMethod: getZoomForResolution
  10238. *
  10239. * Parameters:
  10240. * resolution - {Float}
  10241. * closest - {Boolean} Find the zoom level that corresponds to the absolute
  10242. * closest resolution, which may result in a zoom whose corresponding
  10243. * resolution is actually smaller than we would have desired (if this
  10244. * is being called from a getZoomForExtent() call, then this means that
  10245. * the returned zoom index might not actually contain the entire
  10246. * extent specified... but it'll be close).
  10247. * Default is false.
  10248. *
  10249. * Returns:
  10250. * {Integer} The index of the zoomLevel (entry in the resolutions array)
  10251. * that corresponds to the best fit resolution given the passed in
  10252. * value and the 'closest' specification.
  10253. */
  10254. getZoomForResolution: function(resolution, closest) {
  10255. var zoom, i, len;
  10256. if(this.map.fractionalZoom) {
  10257. var lowZoom = 0;
  10258. var highZoom = this.resolutions.length - 1;
  10259. var highRes = this.resolutions[lowZoom];
  10260. var lowRes = this.resolutions[highZoom];
  10261. var res;
  10262. for(i=0, len=this.resolutions.length; i<len; ++i) {
  10263. res = this.resolutions[i];
  10264. if(res >= resolution) {
  10265. highRes = res;
  10266. lowZoom = i;
  10267. }
  10268. if(res <= resolution) {
  10269. lowRes = res;
  10270. highZoom = i;
  10271. break;
  10272. }
  10273. }
  10274. var dRes = highRes - lowRes;
  10275. if(dRes > 0) {
  10276. zoom = lowZoom + ((highRes - resolution) / dRes);
  10277. } else {
  10278. zoom = lowZoom;
  10279. }
  10280. } else {
  10281. var diff;
  10282. var minDiff = Number.POSITIVE_INFINITY;
  10283. for(i=0, len=this.resolutions.length; i<len; i++) {
  10284. if (closest) {
  10285. diff = Math.abs(this.resolutions[i] - resolution);
  10286. if (diff > minDiff) {
  10287. break;
  10288. }
  10289. minDiff = diff;
  10290. } else {
  10291. if (this.resolutions[i] < resolution) {
  10292. break;
  10293. }
  10294. }
  10295. }
  10296. zoom = Math.max(0, i-1);
  10297. }
  10298. return zoom;
  10299. },
  10300. /**
  10301. * APIMethod: getLonLatFromViewPortPx
  10302. *
  10303. * Parameters:
  10304. * viewPortPx - {<OpenLayers.Pixel>|Object} An OpenLayers.Pixel or
  10305. * an object with a 'x'
  10306. * and 'y' properties.
  10307. *
  10308. * Returns:
  10309. * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in
  10310. * view port <OpenLayers.Pixel>, translated into lon/lat by the layer.
  10311. */
  10312. getLonLatFromViewPortPx: function (viewPortPx) {
  10313. var lonlat = null;
  10314. var map = this.map;
  10315. if (viewPortPx != null && map.minPx) {
  10316. var res = map.getResolution();
  10317. var maxExtent = map.getMaxExtent({restricted: true});
  10318. var lon = (viewPortPx.x - map.minPx.x) * res + maxExtent.left;
  10319. var lat = (map.minPx.y - viewPortPx.y) * res + maxExtent.top;
  10320. lonlat = new OpenLayers.LonLat(lon, lat);
  10321. if (this.wrapDateLine) {
  10322. lonlat = lonlat.wrapDateLine(this.maxExtent);
  10323. }
  10324. }
  10325. return lonlat;
  10326. },
  10327. /**
  10328. * APIMethod: getViewPortPxFromLonLat
  10329. * Returns a pixel location given a map location. This method will return
  10330. * fractional pixel values.
  10331. *
  10332. * Parameters:
  10333. * lonlat - {<OpenLayers.LonLat>|Object} An OpenLayers.LonLat or
  10334. * an object with a 'lon'
  10335. * and 'lat' properties.
  10336. *
  10337. * Returns:
  10338. * {<OpenLayers.Pixel>} An <OpenLayers.Pixel> which is the passed-in
  10339. * lonlat translated into view port pixels.
  10340. */
  10341. getViewPortPxFromLonLat: function (lonlat, resolution) {
  10342. var px = null;
  10343. if (lonlat != null) {
  10344. resolution = resolution || this.map.getResolution();
  10345. var extent = this.map.calculateBounds(null, resolution);
  10346. px = new OpenLayers.Pixel(
  10347. (1/resolution * (lonlat.lon - extent.left)),
  10348. (1/resolution * (extent.top - lonlat.lat))
  10349. );
  10350. }
  10351. return px;
  10352. },
  10353. /**
  10354. * APIMethod: setOpacity
  10355. * Sets the opacity for the entire layer (all images)
  10356. *
  10357. * Parameters:
  10358. * opacity - {Float}
  10359. */
  10360. setOpacity: function(opacity) {
  10361. if (opacity != this.opacity) {
  10362. this.opacity = opacity;
  10363. var childNodes = this.div.childNodes;
  10364. for(var i = 0, len = childNodes.length; i < len; ++i) {
  10365. var element = childNodes[i].firstChild || childNodes[i];
  10366. var lastChild = childNodes[i].lastChild;
  10367. //TODO de-uglify this
  10368. if (lastChild && lastChild.nodeName.toLowerCase() === "iframe") {
  10369. element = lastChild.parentNode;
  10370. }
  10371. OpenLayers.Util.modifyDOMElement(element, null, null, null,
  10372. null, null, null, opacity);
  10373. }
  10374. if (this.map != null) {
  10375. this.map.events.triggerEvent("changelayer", {
  10376. layer: this,
  10377. property: "opacity"
  10378. });
  10379. }
  10380. }
  10381. },
  10382. /**
  10383. * Method: getZIndex
  10384. *
  10385. * Returns:
  10386. * {Integer} the z-index of this layer
  10387. */
  10388. getZIndex: function () {
  10389. return this.div.style.zIndex;
  10390. },
  10391. /**
  10392. * Method: setZIndex
  10393. *
  10394. * Parameters:
  10395. * zIndex - {Integer}
  10396. */
  10397. setZIndex: function (zIndex) {
  10398. this.div.style.zIndex = zIndex;
  10399. },
  10400. /**
  10401. * Method: adjustBounds
  10402. * This function will take a bounds, and if wrapDateLine option is set
  10403. * on the layer, it will return a bounds which is wrapped around the
  10404. * world. We do not wrap for bounds which *cross* the
  10405. * maxExtent.left/right, only bounds which are entirely to the left
  10406. * or entirely to the right.
  10407. *
  10408. * Parameters:
  10409. * bounds - {<OpenLayers.Bounds>}
  10410. */
  10411. adjustBounds: function (bounds) {
  10412. if (this.gutter) {
  10413. // Adjust the extent of a bounds in map units by the
  10414. // layer's gutter in pixels.
  10415. var mapGutter = this.gutter * this.map.getResolution();
  10416. bounds = new OpenLayers.Bounds(bounds.left - mapGutter,
  10417. bounds.bottom - mapGutter,
  10418. bounds.right + mapGutter,
  10419. bounds.top + mapGutter);
  10420. }
  10421. if (this.wrapDateLine) {
  10422. // wrap around the date line, within the limits of rounding error
  10423. var wrappingOptions = {
  10424. 'rightTolerance':this.getResolution(),
  10425. 'leftTolerance':this.getResolution()
  10426. };
  10427. bounds = bounds.wrapDateLine(this.maxExtent, wrappingOptions);
  10428. }
  10429. return bounds;
  10430. },
  10431. CLASS_NAME: "OpenLayers.Layer"
  10432. });
  10433. /* ======================================================================
  10434. OpenLayers/Layer/SphericalMercator.js
  10435. ====================================================================== */
  10436. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  10437. * full list of contributors). Published under the 2-clause BSD license.
  10438. * See license.txt in the OpenLayers distribution or repository for the
  10439. * full text of the license. */
  10440. /**
  10441. * @requires OpenLayers/Layer.js
  10442. * @requires OpenLayers/Projection.js
  10443. */
  10444. /**
  10445. * Class: OpenLayers.Layer.SphericalMercator
  10446. * A mixin for layers that wraps up the pieces neccesary to have a coordinate
  10447. * conversion for working with commercial APIs which use a spherical
  10448. * mercator projection. Using this layer as a base layer, additional
  10449. * layers can be used as overlays if they are in the same projection.
  10450. *
  10451. * A layer is given properties of this object by setting the sphericalMercator
  10452. * property to true.
  10453. *
  10454. * More projection information:
  10455. * - http://spatialreference.org/ref/user/google-projection/
  10456. *
  10457. * Proj4 Text:
  10458. * +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0
  10459. * +k=1.0 +units=m +nadgrids=@null +no_defs
  10460. *
  10461. * WKT:
  10462. * 900913=PROJCS["WGS84 / Simple Mercator", GEOGCS["WGS 84",
  10463. * DATUM["WGS_1984", SPHEROID["WGS_1984", 6378137.0, 298.257223563]],
  10464. * PRIMEM["Greenwich", 0.0], UNIT["degree", 0.017453292519943295],
  10465. * AXIS["Longitude", EAST], AXIS["Latitude", NORTH]],
  10466. * PROJECTION["Mercator_1SP_Google"],
  10467. * PARAMETER["latitude_of_origin", 0.0], PARAMETER["central_meridian", 0.0],
  10468. * PARAMETER["scale_factor", 1.0], PARAMETER["false_easting", 0.0],
  10469. * PARAMETER["false_northing", 0.0], UNIT["m", 1.0], AXIS["x", EAST],
  10470. * AXIS["y", NORTH], AUTHORITY["EPSG","900913"]]
  10471. */
  10472. OpenLayers.Layer.SphericalMercator = {
  10473. /**
  10474. * Method: getExtent
  10475. * Get the map's extent.
  10476. *
  10477. * Returns:
  10478. * {<OpenLayers.Bounds>} The map extent.
  10479. */
  10480. getExtent: function() {
  10481. var extent = null;
  10482. if (this.sphericalMercator) {
  10483. extent = this.map.calculateBounds();
  10484. } else {
  10485. extent = OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this);
  10486. }
  10487. return extent;
  10488. },
  10489. /**
  10490. * Method: getLonLatFromViewPortPx
  10491. * Get a map location from a pixel location
  10492. *
  10493. * Parameters:
  10494. * viewPortPx - {<OpenLayers.Pixel>}
  10495. *
  10496. * Returns:
  10497. * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
  10498. * port OpenLayers.Pixel, translated into lon/lat by map lib
  10499. * If the map lib is not loaded or not centered, returns null
  10500. */
  10501. getLonLatFromViewPortPx: function (viewPortPx) {
  10502. return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this, arguments);
  10503. },
  10504. /**
  10505. * Method: getViewPortPxFromLonLat
  10506. * Get a pixel location from a map location
  10507. *
  10508. * Parameters:
  10509. * lonlat - {<OpenLayers.LonLat>}
  10510. *
  10511. * Returns:
  10512. * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
  10513. * OpenLayers.LonLat, translated into view port pixels by map lib
  10514. * If map lib is not loaded or not centered, returns null
  10515. */
  10516. getViewPortPxFromLonLat: function (lonlat) {
  10517. return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this, arguments);
  10518. },
  10519. /**
  10520. * Method: initMercatorParameters
  10521. * Set up the mercator parameters on the layer: resolutions,
  10522. * projection, units.
  10523. */
  10524. initMercatorParameters: function() {
  10525. // set up properties for Mercator - assume EPSG:900913
  10526. this.RESOLUTIONS = [];
  10527. var maxResolution = 156543.03390625;
  10528. for(var zoom=0; zoom<=this.MAX_ZOOM_LEVEL; ++zoom) {
  10529. this.RESOLUTIONS[zoom] = maxResolution / Math.pow(2, zoom);
  10530. }
  10531. this.units = "m";
  10532. this.projection = this.projection || "EPSG:900913";
  10533. },
  10534. /**
  10535. * APIMethod: forwardMercator
  10536. * Given a lon,lat in EPSG:4326, return a point in Spherical Mercator.
  10537. *
  10538. * Parameters:
  10539. * lon - {float}
  10540. * lat - {float}
  10541. *
  10542. * Returns:
  10543. * {<OpenLayers.LonLat>} The coordinates transformed to Mercator.
  10544. */
  10545. forwardMercator: (function() {
  10546. var gg = new OpenLayers.Projection("EPSG:4326");
  10547. var sm = new OpenLayers.Projection("EPSG:900913");
  10548. return function(lon, lat) {
  10549. var point = OpenLayers.Projection.transform({x: lon, y: lat}, gg, sm);
  10550. return new OpenLayers.LonLat(point.x, point.y);
  10551. };
  10552. })(),
  10553. /**
  10554. * APIMethod: inverseMercator
  10555. * Given a x,y in Spherical Mercator, return a point in EPSG:4326.
  10556. *
  10557. * Parameters:
  10558. * x - {float} A map x in Spherical Mercator.
  10559. * y - {float} A map y in Spherical Mercator.
  10560. *
  10561. * Returns:
  10562. * {<OpenLayers.LonLat>} The coordinates transformed to EPSG:4326.
  10563. */
  10564. inverseMercator: (function() {
  10565. var gg = new OpenLayers.Projection("EPSG:4326");
  10566. var sm = new OpenLayers.Projection("EPSG:900913");
  10567. return function(x, y) {
  10568. var point = OpenLayers.Projection.transform({x: x, y: y}, sm, gg);
  10569. return new OpenLayers.LonLat(point.x, point.y);
  10570. };
  10571. })()
  10572. };
  10573. /* ======================================================================
  10574. OpenLayers/Layer/EventPane.js
  10575. ====================================================================== */
  10576. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  10577. * full list of contributors). Published under the 2-clause BSD license.
  10578. * See license.txt in the OpenLayers distribution or repository for the
  10579. * full text of the license. */
  10580. /**
  10581. * @requires OpenLayers/Layer.js
  10582. * @requires OpenLayers/Util.js
  10583. */
  10584. /**
  10585. * Class: OpenLayers.Layer.EventPane
  10586. * Base class for 3rd party layers, providing a DOM element which isolates
  10587. * the 3rd-party layer from mouse events.
  10588. * Only used by Google layers.
  10589. *
  10590. * Automatically instantiated by the Google constructor, and not usually instantiated directly.
  10591. *
  10592. * Create a new event pane layer with the
  10593. * <OpenLayers.Layer.EventPane> constructor.
  10594. *
  10595. * Inherits from:
  10596. * - <OpenLayers.Layer>
  10597. */
  10598. OpenLayers.Layer.EventPane = OpenLayers.Class(OpenLayers.Layer, {
  10599. /**
  10600. * APIProperty: smoothDragPan
  10601. * {Boolean} smoothDragPan determines whether non-public/internal API
  10602. * methods are used for better performance while dragging EventPane
  10603. * layers. When not in sphericalMercator mode, the smoother dragging
  10604. * doesn't actually move north/south directly with the number of
  10605. * pixels moved, resulting in a slight offset when you drag your mouse
  10606. * north south with this option on. If this visual disparity bothers
  10607. * you, you should turn this option off, or use spherical mercator.
  10608. * Default is on.
  10609. */
  10610. smoothDragPan: true,
  10611. /**
  10612. * Property: isBaseLayer
  10613. * {Boolean} EventPaned layers are always base layers, by necessity.
  10614. */
  10615. isBaseLayer: true,
  10616. /**
  10617. * APIProperty: isFixed
  10618. * {Boolean} EventPaned layers are fixed by default.
  10619. */
  10620. isFixed: true,
  10621. /**
  10622. * Property: pane
  10623. * {DOMElement} A reference to the element that controls the events.
  10624. */
  10625. pane: null,
  10626. /**
  10627. * Property: mapObject
  10628. * {Object} This is the object which will be used to load the 3rd party library
  10629. * in the case of the google layer, this will be of type GMap,
  10630. * in the case of the ve layer, this will be of type VEMap
  10631. */
  10632. mapObject: null,
  10633. /**
  10634. * Constructor: OpenLayers.Layer.EventPane
  10635. * Create a new event pane layer
  10636. *
  10637. * Parameters:
  10638. * name - {String}
  10639. * options - {Object} Hashtable of extra options to tag onto the layer
  10640. */
  10641. initialize: function(name, options) {
  10642. OpenLayers.Layer.prototype.initialize.apply(this, arguments);
  10643. if (this.pane == null) {
  10644. this.pane = OpenLayers.Util.createDiv(this.div.id + "_EventPane");
  10645. }
  10646. },
  10647. /**
  10648. * APIMethod: destroy
  10649. * Deconstruct this layer.
  10650. */
  10651. destroy: function() {
  10652. this.mapObject = null;
  10653. this.pane = null;
  10654. OpenLayers.Layer.prototype.destroy.apply(this, arguments);
  10655. },
  10656. /**
  10657. * Method: setMap
  10658. * Set the map property for the layer. This is done through an accessor
  10659. * so that subclasses can override this and take special action once
  10660. * they have their map variable set.
  10661. *
  10662. * Parameters:
  10663. * map - {<OpenLayers.Map>}
  10664. */
  10665. setMap: function(map) {
  10666. OpenLayers.Layer.prototype.setMap.apply(this, arguments);
  10667. this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
  10668. this.pane.style.display = this.div.style.display;
  10669. this.pane.style.width="100%";
  10670. this.pane.style.height="100%";
  10671. if (OpenLayers.BROWSER_NAME == "msie") {
  10672. this.pane.style.background =
  10673. "url(" + OpenLayers.Util.getImageLocation("blank.gif") + ")";
  10674. }
  10675. if (this.isFixed) {
  10676. this.map.viewPortDiv.appendChild(this.pane);
  10677. } else {
  10678. this.map.layerContainerDiv.appendChild(this.pane);
  10679. }
  10680. // once our layer has been added to the map, we can load it
  10681. this.loadMapObject();
  10682. // if map didn't load, display warning
  10683. if (this.mapObject == null) {
  10684. this.loadWarningMessage();
  10685. }
  10686. },
  10687. /**
  10688. * APIMethod: removeMap
  10689. * On being removed from the map, we'll like to remove the invisible 'pane'
  10690. * div that we added to it on creation.
  10691. *
  10692. * Parameters:
  10693. * map - {<OpenLayers.Map>}
  10694. */
  10695. removeMap: function(map) {
  10696. if (this.pane && this.pane.parentNode) {
  10697. this.pane.parentNode.removeChild(this.pane);
  10698. }
  10699. OpenLayers.Layer.prototype.removeMap.apply(this, arguments);
  10700. },
  10701. /**
  10702. * Method: loadWarningMessage
  10703. * If we can't load the map lib, then display an error message to the
  10704. * user and tell them where to go for help.
  10705. *
  10706. * This function sets up the layout for the warning message. Each 3rd
  10707. * party layer must implement its own getWarningHTML() function to
  10708. * provide the actual warning message.
  10709. */
  10710. loadWarningMessage:function() {
  10711. this.div.style.backgroundColor = "darkblue";
  10712. var viewSize = this.map.getSize();
  10713. var msgW = Math.min(viewSize.w, 300);
  10714. var msgH = Math.min(viewSize.h, 200);
  10715. var size = new OpenLayers.Size(msgW, msgH);
  10716. var centerPx = new OpenLayers.Pixel(viewSize.w/2, viewSize.h/2);
  10717. var topLeft = centerPx.add(-size.w/2, -size.h/2);
  10718. var div = OpenLayers.Util.createDiv(this.name + "_warning",
  10719. topLeft,
  10720. size,
  10721. null,
  10722. null,
  10723. null,
  10724. "auto");
  10725. div.style.padding = "7px";
  10726. div.style.backgroundColor = "yellow";
  10727. div.innerHTML = this.getWarningHTML();
  10728. this.div.appendChild(div);
  10729. },
  10730. /**
  10731. * Method: getWarningHTML
  10732. * To be implemented by subclasses.
  10733. *
  10734. * Returns:
  10735. * {String} String with information on why layer is broken, how to get
  10736. * it working.
  10737. */
  10738. getWarningHTML:function() {
  10739. //should be implemented by subclasses
  10740. return "";
  10741. },
  10742. /**
  10743. * Method: display
  10744. * Set the display on the pane
  10745. *
  10746. * Parameters:
  10747. * display - {Boolean}
  10748. */
  10749. display: function(display) {
  10750. OpenLayers.Layer.prototype.display.apply(this, arguments);
  10751. this.pane.style.display = this.div.style.display;
  10752. },
  10753. /**
  10754. * Method: setZIndex
  10755. * Set the z-index order for the pane.
  10756. *
  10757. * Parameters:
  10758. * zIndex - {int}
  10759. */
  10760. setZIndex: function (zIndex) {
  10761. OpenLayers.Layer.prototype.setZIndex.apply(this, arguments);
  10762. this.pane.style.zIndex = parseInt(this.div.style.zIndex) + 1;
  10763. },
  10764. /**
  10765. * Method: moveByPx
  10766. * Move the layer based on pixel vector. To be implemented by subclasses.
  10767. *
  10768. * Parameters:
  10769. * dx - {Number} The x coord of the displacement vector.
  10770. * dy - {Number} The y coord of the displacement vector.
  10771. */
  10772. moveByPx: function(dx, dy) {
  10773. OpenLayers.Layer.prototype.moveByPx.apply(this, arguments);
  10774. if (this.dragPanMapObject) {
  10775. this.dragPanMapObject(dx, -dy);
  10776. } else {
  10777. this.moveTo(this.map.getCachedCenter());
  10778. }
  10779. },
  10780. /**
  10781. * Method: moveTo
  10782. * Handle calls to move the layer.
  10783. *
  10784. * Parameters:
  10785. * bounds - {<OpenLayers.Bounds>}
  10786. * zoomChanged - {Boolean}
  10787. * dragging - {Boolean}
  10788. */
  10789. moveTo:function(bounds, zoomChanged, dragging) {
  10790. OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
  10791. if (this.mapObject != null) {
  10792. var newCenter = this.map.getCenter();
  10793. var newZoom = this.map.getZoom();
  10794. if (newCenter != null) {
  10795. var moOldCenter = this.getMapObjectCenter();
  10796. var oldCenter = this.getOLLonLatFromMapObjectLonLat(moOldCenter);
  10797. var moOldZoom = this.getMapObjectZoom();
  10798. var oldZoom= this.getOLZoomFromMapObjectZoom(moOldZoom);
  10799. if (!(newCenter.equals(oldCenter)) || newZoom != oldZoom) {
  10800. if (!zoomChanged && oldCenter && this.dragPanMapObject &&
  10801. this.smoothDragPan) {
  10802. var oldPx = this.map.getViewPortPxFromLonLat(oldCenter);
  10803. var newPx = this.map.getViewPortPxFromLonLat(newCenter);
  10804. this.dragPanMapObject(newPx.x-oldPx.x, oldPx.y-newPx.y);
  10805. } else {
  10806. var center = this.getMapObjectLonLatFromOLLonLat(newCenter);
  10807. var zoom = this.getMapObjectZoomFromOLZoom(newZoom);
  10808. this.setMapObjectCenter(center, zoom, dragging);
  10809. }
  10810. }
  10811. }
  10812. }
  10813. },
  10814. /********************************************************/
  10815. /* */
  10816. /* Baselayer Functions */
  10817. /* */
  10818. /********************************************************/
  10819. /**
  10820. * Method: getLonLatFromViewPortPx
  10821. * Get a map location from a pixel location
  10822. *
  10823. * Parameters:
  10824. * viewPortPx - {<OpenLayers.Pixel>}
  10825. *
  10826. * Returns:
  10827. * {<OpenLayers.LonLat>} An OpenLayers.LonLat which is the passed-in view
  10828. * port OpenLayers.Pixel, translated into lon/lat by map lib
  10829. * If the map lib is not loaded or not centered, returns null
  10830. */
  10831. getLonLatFromViewPortPx: function (viewPortPx) {
  10832. var lonlat = null;
  10833. if ( (this.mapObject != null) &&
  10834. (this.getMapObjectCenter() != null) ) {
  10835. var moPixel = this.getMapObjectPixelFromOLPixel(viewPortPx);
  10836. var moLonLat = this.getMapObjectLonLatFromMapObjectPixel(moPixel);
  10837. lonlat = this.getOLLonLatFromMapObjectLonLat(moLonLat);
  10838. }
  10839. return lonlat;
  10840. },
  10841. /**
  10842. * Method: getViewPortPxFromLonLat
  10843. * Get a pixel location from a map location
  10844. *
  10845. * Parameters:
  10846. * lonlat - {<OpenLayers.LonLat>}
  10847. *
  10848. * Returns:
  10849. * {<OpenLayers.Pixel>} An OpenLayers.Pixel which is the passed-in
  10850. * OpenLayers.LonLat, translated into view port pixels by map lib
  10851. * If map lib is not loaded or not centered, returns null
  10852. */
  10853. getViewPortPxFromLonLat: function (lonlat) {
  10854. var viewPortPx = null;
  10855. if ( (this.mapObject != null) &&
  10856. (this.getMapObjectCenter() != null) ) {
  10857. var moLonLat = this.getMapObjectLonLatFromOLLonLat(lonlat);
  10858. var moPixel = this.getMapObjectPixelFromMapObjectLonLat(moLonLat);
  10859. viewPortPx = this.getOLPixelFromMapObjectPixel(moPixel);
  10860. }
  10861. return viewPortPx;
  10862. },
  10863. /********************************************************/
  10864. /* */
  10865. /* Translation Functions */
  10866. /* */
  10867. /* The following functions translate Map Object and */
  10868. /* OL formats for Pixel, LonLat */
  10869. /* */
  10870. /********************************************************/
  10871. //
  10872. // TRANSLATION: MapObject LatLng <-> OpenLayers.LonLat
  10873. //
  10874. /**
  10875. * Method: getOLLonLatFromMapObjectLonLat
  10876. * Get an OL style map location from a 3rd party style map location
  10877. *
  10878. * Parameters
  10879. * moLonLat - {Object}
  10880. *
  10881. * Returns:
  10882. * {<OpenLayers.LonLat>} An OpenLayers.LonLat, translated from the passed in
  10883. * MapObject LonLat
  10884. * Returns null if null value is passed in
  10885. */
  10886. getOLLonLatFromMapObjectLonLat: function(moLonLat) {
  10887. var olLonLat = null;
  10888. if (moLonLat != null) {
  10889. var lon = this.getLongitudeFromMapObjectLonLat(moLonLat);
  10890. var lat = this.getLatitudeFromMapObjectLonLat(moLonLat);
  10891. olLonLat = new OpenLayers.LonLat(lon, lat);
  10892. }
  10893. return olLonLat;
  10894. },
  10895. /**
  10896. * Method: getMapObjectLonLatFromOLLonLat
  10897. * Get a 3rd party map location from an OL map location.
  10898. *
  10899. * Parameters:
  10900. * olLonLat - {<OpenLayers.LonLat>}
  10901. *
  10902. * Returns:
  10903. * {Object} A MapObject LonLat, translated from the passed in
  10904. * OpenLayers.LonLat
  10905. * Returns null if null value is passed in
  10906. */
  10907. getMapObjectLonLatFromOLLonLat: function(olLonLat) {
  10908. var moLatLng = null;
  10909. if (olLonLat != null) {
  10910. moLatLng = this.getMapObjectLonLatFromLonLat(olLonLat.lon,
  10911. olLonLat.lat);
  10912. }
  10913. return moLatLng;
  10914. },
  10915. //
  10916. // TRANSLATION: MapObject Pixel <-> OpenLayers.Pixel
  10917. //
  10918. /**
  10919. * Method: getOLPixelFromMapObjectPixel
  10920. * Get an OL pixel location from a 3rd party pixel location.
  10921. *
  10922. * Parameters:
  10923. * moPixel - {Object}
  10924. *
  10925. * Returns:
  10926. * {<OpenLayers.Pixel>} An OpenLayers.Pixel, translated from the passed in
  10927. * MapObject Pixel
  10928. * Returns null if null value is passed in
  10929. */
  10930. getOLPixelFromMapObjectPixel: function(moPixel) {
  10931. var olPixel = null;
  10932. if (moPixel != null) {
  10933. var x = this.getXFromMapObjectPixel(moPixel);
  10934. var y = this.getYFromMapObjectPixel(moPixel);
  10935. olPixel = new OpenLayers.Pixel(x, y);
  10936. }
  10937. return olPixel;
  10938. },
  10939. /**
  10940. * Method: getMapObjectPixelFromOLPixel
  10941. * Get a 3rd party pixel location from an OL pixel location
  10942. *
  10943. * Parameters:
  10944. * olPixel - {<OpenLayers.Pixel>}
  10945. *
  10946. * Returns:
  10947. * {Object} A MapObject Pixel, translated from the passed in
  10948. * OpenLayers.Pixel
  10949. * Returns null if null value is passed in
  10950. */
  10951. getMapObjectPixelFromOLPixel: function(olPixel) {
  10952. var moPixel = null;
  10953. if (olPixel != null) {
  10954. moPixel = this.getMapObjectPixelFromXY(olPixel.x, olPixel.y);
  10955. }
  10956. return moPixel;
  10957. },
  10958. CLASS_NAME: "OpenLayers.Layer.EventPane"
  10959. });
  10960. /* ======================================================================
  10961. OpenLayers/Layer/FixedZoomLevels.js
  10962. ====================================================================== */
  10963. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  10964. * full list of contributors). Published under the 2-clause BSD license.
  10965. * See license.txt in the OpenLayers distribution or repository for the
  10966. * full text of the license. */
  10967. /**
  10968. * @requires OpenLayers/Layer.js
  10969. */
  10970. /**
  10971. * Class: OpenLayers.Layer.FixedZoomLevels
  10972. * Some Layers will already have established zoom levels (like google
  10973. * or ve). Instead of trying to determine them and populate a resolutions[]
  10974. * Array with those values, we will hijack the resolution functionality
  10975. * here.
  10976. *
  10977. * When you subclass FixedZoomLevels:
  10978. *
  10979. * The initResolutions() call gets nullified, meaning no resolutions[] array
  10980. * is set up. Which would be a big problem getResolution() in Layer, since
  10981. * it merely takes map.zoom and indexes into resolutions[]... but....
  10982. *
  10983. * The getResolution() call is also overridden. Instead of using the
  10984. * resolutions[] array, we simply calculate the current resolution based
  10985. * on the current extent and the current map size. But how will we be able
  10986. * to calculate the current extent without knowing the resolution...?
  10987. *
  10988. * The getExtent() function is also overridden. Instead of calculating extent
  10989. * based on the center point and the current resolution, we instead
  10990. * calculate the extent by getting the lonlats at the top-left and
  10991. * bottom-right by using the getLonLatFromViewPortPx() translation function,
  10992. * taken from the pixel locations (0,0) and the size of the map. But how
  10993. * will we be able to do lonlat-px translation without resolution....?
  10994. *
  10995. * The getZoomForResolution() method is overridden. Instead of indexing into
  10996. * the resolutions[] array, we call OpenLayers.Layer.getExent(), passing in
  10997. * the desired resolution. With this extent, we then call getZoomForExtent()
  10998. *
  10999. *
  11000. * Whenever you implement a layer using OpenLayers.Layer.FixedZoomLevels,
  11001. * it is your responsibility to provide the following three functions:
  11002. *
  11003. * - getLonLatFromViewPortPx
  11004. * - getViewPortPxFromLonLat
  11005. * - getZoomForExtent
  11006. *
  11007. * ...those three functions should generally be provided by any reasonable
  11008. * API that you might be working from.
  11009. *
  11010. */
  11011. OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
  11012. /********************************************************/
  11013. /* */
  11014. /* Baselayer Functions */
  11015. /* */
  11016. /* The following functions must all be implemented */
  11017. /* by all base layers */
  11018. /* */
  11019. /********************************************************/
  11020. /**
  11021. * Constructor: OpenLayers.Layer.FixedZoomLevels
  11022. * Create a new fixed zoom levels layer.
  11023. */
  11024. initialize: function() {
  11025. //this class is only just to add the following functions...
  11026. // nothing to actually do here... but it is probably a good
  11027. // idea to have layers that use these functions call this
  11028. // inititalize() anyways, in case at some point we decide we
  11029. // do want to put some functionality or state in here.
  11030. },
  11031. /**
  11032. * Method: initResolutions
  11033. * Populate the resolutions array
  11034. */
  11035. initResolutions: function() {
  11036. var props = ['minZoomLevel', 'maxZoomLevel', 'numZoomLevels'];
  11037. for(var i=0, len=props.length; i<len; i++) {
  11038. var property = props[i];
  11039. this[property] = (this.options[property] != null)
  11040. ? this.options[property]
  11041. : this.map[property];
  11042. }
  11043. if ( (this.minZoomLevel == null) ||
  11044. (this.minZoomLevel < this.MIN_ZOOM_LEVEL) ){
  11045. this.minZoomLevel = this.MIN_ZOOM_LEVEL;
  11046. }
  11047. //
  11048. // At this point, we know what the minimum desired zoom level is, and
  11049. // we must calculate the total number of zoom levels.
  11050. //
  11051. // Because we allow for the setting of either the 'numZoomLevels'
  11052. // or the 'maxZoomLevel' properties... on either the layer or the
  11053. // map, we have to define some rules to see which we take into
  11054. // account first in this calculation.
  11055. //
  11056. // The following is the precedence list for these properties:
  11057. //
  11058. // (1) numZoomLevels set on layer
  11059. // (2) maxZoomLevel set on layer
  11060. // (3) numZoomLevels set on map
  11061. // (4) maxZoomLevel set on map*
  11062. // (5) none of the above*
  11063. //
  11064. // *Note that options (4) and (5) are only possible if the user
  11065. // _explicitly_ sets the 'numZoomLevels' property on the map to
  11066. // null, since it is set by default to 16.
  11067. //
  11068. //
  11069. // Note to future: In 3.0, I think we should remove the default
  11070. // value of 16 for map.numZoomLevels. Rather, I think that value
  11071. // should be set as a default on the Layer.WMS class. If someone
  11072. // creates a 3rd party layer and does not specify any 'minZoomLevel',
  11073. // 'maxZoomLevel', or 'numZoomLevels', and has not explicitly
  11074. // specified any of those on the map object either.. then I think
  11075. // it is fair to say that s/he wants all the zoom levels available.
  11076. //
  11077. // By making map.numZoomLevels *null* by default, that will be the
  11078. // case. As it is, I don't feel comfortable changing that right now
  11079. // as it would be a glaring API change and actually would probably
  11080. // break many peoples' codes.
  11081. //
  11082. //the number of zoom levels we'd like to have.
  11083. var desiredZoomLevels;
  11084. //this is the maximum number of zoom levels the layer will allow,
  11085. // given the specified starting minimum zoom level.
  11086. var limitZoomLevels = this.MAX_ZOOM_LEVEL - this.minZoomLevel + 1;
  11087. if ( ((this.options.numZoomLevels == null) &&
  11088. (this.options.maxZoomLevel != null)) // (2)
  11089. ||
  11090. ((this.numZoomLevels == null) &&
  11091. (this.maxZoomLevel != null)) // (4)
  11092. ) {
  11093. //calculate based on specified maxZoomLevel (on layer or map)
  11094. desiredZoomLevels = this.maxZoomLevel - this.minZoomLevel + 1;
  11095. } else {
  11096. //calculate based on specified numZoomLevels (on layer or map)
  11097. // this covers cases (1) and (3)
  11098. desiredZoomLevels = this.numZoomLevels;
  11099. }
  11100. if (desiredZoomLevels != null) {
  11101. //Now that we know what we would *like* the number of zoom levels
  11102. // to be, based on layer or map options, we have to make sure that
  11103. // it does not conflict with the actual limit, as specified by
  11104. // the constants on the layer itself (and calculated into the
  11105. // 'limitZoomLevels' variable).
  11106. this.numZoomLevels = Math.min(desiredZoomLevels, limitZoomLevels);
  11107. } else {
  11108. // case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
  11109. // set on either the layer or the map. So we just use the
  11110. // maximum limit as calculated by the layer's constants.
  11111. this.numZoomLevels = limitZoomLevels;
  11112. }
  11113. //now that the 'numZoomLevels' is appropriately, safely set,
  11114. // we go back and re-calculate the 'maxZoomLevel'.
  11115. this.maxZoomLevel = this.minZoomLevel + this.numZoomLevels - 1;
  11116. if (this.RESOLUTIONS != null) {
  11117. var resolutionsIndex = 0;
  11118. this.resolutions = [];
  11119. for(var i= this.minZoomLevel; i <= this.maxZoomLevel; i++) {
  11120. this.resolutions[resolutionsIndex++] = this.RESOLUTIONS[i];
  11121. }
  11122. this.maxResolution = this.resolutions[0];
  11123. this.minResolution = this.resolutions[this.resolutions.length - 1];
  11124. }
  11125. },
  11126. /**
  11127. * APIMethod: getResolution
  11128. * Get the current map resolution
  11129. *
  11130. * Returns:
  11131. * {Float} Map units per Pixel
  11132. */
  11133. getResolution: function() {
  11134. if (this.resolutions != null) {
  11135. return OpenLayers.Layer.prototype.getResolution.apply(this, arguments);
  11136. } else {
  11137. var resolution = null;
  11138. var viewSize = this.map.getSize();
  11139. var extent = this.getExtent();
  11140. if ((viewSize != null) && (extent != null)) {
  11141. resolution = Math.max( extent.getWidth() / viewSize.w,
  11142. extent.getHeight() / viewSize.h );
  11143. }
  11144. return resolution;
  11145. }
  11146. },
  11147. /**
  11148. * APIMethod: getExtent
  11149. * Calculates using px-> lonlat translation functions on tl and br
  11150. * corners of viewport
  11151. *
  11152. * Returns:
  11153. * {<OpenLayers.Bounds>} A Bounds object which represents the lon/lat
  11154. * bounds of the current viewPort.
  11155. */
  11156. getExtent: function () {
  11157. var size = this.map.getSize();
  11158. var tl = this.getLonLatFromViewPortPx({
  11159. x: 0, y: 0
  11160. });
  11161. var br = this.getLonLatFromViewPortPx({
  11162. x: size.w, y: size.h
  11163. });
  11164. if ((tl != null) && (br != null)) {
  11165. return new OpenLayers.Bounds(tl.lon, br.lat, br.lon, tl.lat);
  11166. } else {
  11167. return null;
  11168. }
  11169. },
  11170. /**
  11171. * Method: getZoomForResolution
  11172. * Get the zoom level for a given resolution
  11173. *
  11174. * Parameters:
  11175. * resolution - {Float}
  11176. *
  11177. * Returns:
  11178. * {Integer} A suitable zoom level for the specified resolution.
  11179. * If no baselayer is set, returns null.
  11180. */
  11181. getZoomForResolution: function(resolution) {
  11182. if (this.resolutions != null) {
  11183. return OpenLayers.Layer.prototype.getZoomForResolution.apply(this, arguments);
  11184. } else {
  11185. var extent = OpenLayers.Layer.prototype.getExtent.apply(this, []);
  11186. return this.getZoomForExtent(extent);
  11187. }
  11188. },
  11189. /********************************************************/
  11190. /* */
  11191. /* Translation Functions */
  11192. /* */
  11193. /* The following functions translate GMaps and OL */
  11194. /* formats for Pixel, LonLat, Bounds, and Zoom */
  11195. /* */
  11196. /********************************************************/
  11197. //
  11198. // TRANSLATION: MapObject Zoom <-> OpenLayers Zoom
  11199. //
  11200. /**
  11201. * Method: getOLZoomFromMapObjectZoom
  11202. * Get the OL zoom index from the map object zoom level
  11203. *
  11204. * Parameters:
  11205. * moZoom - {Integer}
  11206. *
  11207. * Returns:
  11208. * {Integer} An OpenLayers Zoom level, translated from the passed in zoom
  11209. * Returns null if null value is passed in
  11210. */
  11211. getOLZoomFromMapObjectZoom: function(moZoom) {
  11212. var zoom = null;
  11213. if (moZoom != null) {
  11214. zoom = moZoom - this.minZoomLevel;
  11215. if (this.map.baseLayer !== this) {
  11216. zoom = this.map.baseLayer.getZoomForResolution(
  11217. this.getResolutionForZoom(zoom)
  11218. );
  11219. }
  11220. }
  11221. return zoom;
  11222. },
  11223. /**
  11224. * Method: getMapObjectZoomFromOLZoom
  11225. * Get the map object zoom level from the OL zoom level
  11226. *
  11227. * Parameters:
  11228. * olZoom - {Integer}
  11229. *
  11230. * Returns:
  11231. * {Integer} A MapObject level, translated from the passed in olZoom
  11232. * Returns null if null value is passed in
  11233. */
  11234. getMapObjectZoomFromOLZoom: function(olZoom) {
  11235. var zoom = null;
  11236. if (olZoom != null) {
  11237. zoom = olZoom + this.minZoomLevel;
  11238. if (this.map.baseLayer !== this) {
  11239. zoom = this.getZoomForResolution(
  11240. this.map.baseLayer.getResolutionForZoom(zoom)
  11241. );
  11242. }
  11243. }
  11244. return zoom;
  11245. },
  11246. CLASS_NAME: "OpenLayers.Layer.FixedZoomLevels"
  11247. });
  11248. /* ======================================================================
  11249. OpenLayers/Layer/Google.js
  11250. ====================================================================== */
  11251. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  11252. * full list of contributors). Published under the 2-clause BSD license.
  11253. * See license.txt in the OpenLayers distribution or repository for the
  11254. * full text of the license. */
  11255. /**
  11256. * @requires OpenLayers/Layer/SphericalMercator.js
  11257. * @requires OpenLayers/Layer/EventPane.js
  11258. * @requires OpenLayers/Layer/FixedZoomLevels.js
  11259. * @requires OpenLayers/Lang.js
  11260. */
  11261. /**
  11262. * Class: OpenLayers.Layer.Google
  11263. *
  11264. * Provides a wrapper for Google's Maps API
  11265. * Normally the Terms of Use for this API do not allow wrapping, but Google
  11266. * have provided written consent to OpenLayers for this - see email in
  11267. * http://osgeo-org.1560.n6.nabble.com/Google-Maps-API-Terms-of-Use-changes-tp4910013p4911981.html
  11268. *
  11269. * Inherits from:
  11270. * - <OpenLayers.Layer.SphericalMercator>
  11271. * - <OpenLayers.Layer.EventPane>
  11272. * - <OpenLayers.Layer.FixedZoomLevels>
  11273. */
  11274. OpenLayers.Layer.Google = OpenLayers.Class(
  11275. OpenLayers.Layer.EventPane,
  11276. OpenLayers.Layer.FixedZoomLevels, {
  11277. /**
  11278. * Constant: MIN_ZOOM_LEVEL
  11279. * {Integer} 0
  11280. */
  11281. MIN_ZOOM_LEVEL: 0,
  11282. /**
  11283. * Constant: MAX_ZOOM_LEVEL
  11284. * {Integer} 21
  11285. */
  11286. MAX_ZOOM_LEVEL: 21,
  11287. /**
  11288. * Constant: RESOLUTIONS
  11289. * {Array(Float)} Hardcode these resolutions so that they are more closely
  11290. * tied with the standard wms projection
  11291. */
  11292. RESOLUTIONS: [
  11293. 1.40625,
  11294. 0.703125,
  11295. 0.3515625,
  11296. 0.17578125,
  11297. 0.087890625,
  11298. 0.0439453125,
  11299. 0.02197265625,
  11300. 0.010986328125,
  11301. 0.0054931640625,
  11302. 0.00274658203125,
  11303. 0.001373291015625,
  11304. 0.0006866455078125,
  11305. 0.00034332275390625,
  11306. 0.000171661376953125,
  11307. 0.0000858306884765625,
  11308. 0.00004291534423828125,
  11309. 0.00002145767211914062,
  11310. 0.00001072883605957031,
  11311. 0.00000536441802978515,
  11312. 0.00000268220901489257,
  11313. 0.0000013411045074462891,
  11314. 0.00000067055225372314453
  11315. ],
  11316. /**
  11317. * APIProperty: type
  11318. * {GMapType}
  11319. */
  11320. type: null,
  11321. /**
  11322. * APIProperty: wrapDateLine
  11323. * {Boolean} Allow user to pan forever east/west. Default is true.
  11324. * Setting this to false only restricts panning if
  11325. * <sphericalMercator> is true.
  11326. */
  11327. wrapDateLine: true,
  11328. /**
  11329. * APIProperty: sphericalMercator
  11330. * {Boolean} Should the map act as a mercator-projected map? This will
  11331. * cause all interactions with the map to be in the actual map
  11332. * projection, which allows support for vector drawing, overlaying
  11333. * other maps, etc.
  11334. */
  11335. sphericalMercator: false,
  11336. /**
  11337. * Property: version
  11338. * {Number} The version of the Google Maps API
  11339. */
  11340. version: null,
  11341. /**
  11342. * Constructor: OpenLayers.Layer.Google
  11343. *
  11344. * Parameters:
  11345. * name - {String} A name for the layer.
  11346. * options - {Object} An optional object whose properties will be set
  11347. * on the layer.
  11348. */
  11349. initialize: function(name, options) {
  11350. options = options || {};
  11351. if(!options.version) {
  11352. options.version = typeof GMap2 === "function" ? "2" : "3";
  11353. }
  11354. var mixin = OpenLayers.Layer.Google["v" +
  11355. options.version.replace(/\./g, "_")];
  11356. if (mixin) {
  11357. OpenLayers.Util.applyDefaults(options, mixin);
  11358. } else {
  11359. throw "Unsupported Google Maps API version: " + options.version;
  11360. }
  11361. OpenLayers.Util.applyDefaults(options, mixin.DEFAULTS);
  11362. if (options.maxExtent) {
  11363. options.maxExtent = options.maxExtent.clone();
  11364. }
  11365. OpenLayers.Layer.EventPane.prototype.initialize.apply(this,
  11366. [name, options]);
  11367. OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
  11368. [name, options]);
  11369. if (this.sphericalMercator) {
  11370. OpenLayers.Util.extend(this, OpenLayers.Layer.SphericalMercator);
  11371. this.initMercatorParameters();
  11372. }
  11373. },
  11374. /**
  11375. * Method: clone
  11376. * Create a clone of this layer
  11377. *
  11378. * Returns:
  11379. * {<OpenLayers.Layer.Google>} An exact clone of this layer
  11380. */
  11381. clone: function() {
  11382. /**
  11383. * This method isn't intended to be called by a subclass and it
  11384. * doesn't call the same method on the superclass. We don't call
  11385. * the super's clone because we don't want properties that are set
  11386. * on this layer after initialize (i.e. this.mapObject etc.).
  11387. */
  11388. return new OpenLayers.Layer.Google(
  11389. this.name, this.getOptions()
  11390. );
  11391. },
  11392. /**
  11393. * APIMethod: setVisibility
  11394. * Set the visibility flag for the layer and hide/show & redraw
  11395. * accordingly. Fire event unless otherwise specified
  11396. *
  11397. * Note that visibility is no longer simply whether or not the layer's
  11398. * style.display is set to "block". Now we store a 'visibility' state
  11399. * property on the layer class, this allows us to remember whether or
  11400. * not we *desire* for a layer to be visible. In the case where the
  11401. * map's resolution is out of the layer's range, this desire may be
  11402. * subverted.
  11403. *
  11404. * Parameters:
  11405. * visible - {Boolean} Display the layer (if in range)
  11406. */
  11407. setVisibility: function(visible) {
  11408. // sharing a map container, opacity has to be set per layer
  11409. var opacity = this.opacity == null ? 1 : this.opacity;
  11410. OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this, arguments);
  11411. this.setOpacity(opacity);
  11412. },
  11413. /**
  11414. * APIMethod: display
  11415. * Hide or show the Layer
  11416. *
  11417. * Parameters:
  11418. * visible - {Boolean}
  11419. */
  11420. display: function(visible) {
  11421. if (!this._dragging) {
  11422. this.setGMapVisibility(visible);
  11423. }
  11424. OpenLayers.Layer.EventPane.prototype.display.apply(this, arguments);
  11425. },
  11426. /**
  11427. * Method: moveTo
  11428. *
  11429. * Parameters:
  11430. * bounds - {<OpenLayers.Bounds>}
  11431. * zoomChanged - {Boolean} Tells when zoom has changed, as layers have to
  11432. * do some init work in that case.
  11433. * dragging - {Boolean}
  11434. */
  11435. moveTo: function(bounds, zoomChanged, dragging) {
  11436. this._dragging = dragging;
  11437. OpenLayers.Layer.EventPane.prototype.moveTo.apply(this, arguments);
  11438. delete this._dragging;
  11439. },
  11440. /**
  11441. * APIMethod: setOpacity
  11442. * Sets the opacity for the entire layer (all images)
  11443. *
  11444. * Parameters:
  11445. * opacity - {Float}
  11446. */
  11447. setOpacity: function(opacity) {
  11448. if (opacity !== this.opacity) {
  11449. if (this.map != null) {
  11450. this.map.events.triggerEvent("changelayer", {
  11451. layer: this,
  11452. property: "opacity"
  11453. });
  11454. }
  11455. this.opacity = opacity;
  11456. }
  11457. // Though this layer's opacity may not change, we're sharing a container
  11458. // and need to update the opacity for the entire container.
  11459. if (this.getVisibility()) {
  11460. var container = this.getMapContainer();
  11461. OpenLayers.Util.modifyDOMElement(
  11462. container, null, null, null, null, null, null, opacity
  11463. );
  11464. }
  11465. },
  11466. /**
  11467. * APIMethod: destroy
  11468. * Clean up this layer.
  11469. */
  11470. destroy: function() {
  11471. /**
  11472. * We have to override this method because the event pane destroy
  11473. * deletes the mapObject reference before removing this layer from
  11474. * the map.
  11475. */
  11476. if (this.map) {
  11477. this.setGMapVisibility(false);
  11478. var cache = OpenLayers.Layer.Google.cache[this.map.id];
  11479. if (cache && cache.count <= 1) {
  11480. this.removeGMapElements();
  11481. }
  11482. }
  11483. OpenLayers.Layer.EventPane.prototype.destroy.apply(this, arguments);
  11484. },
  11485. /**
  11486. * Method: removeGMapElements
  11487. * Remove all elements added to the dom. This should only be called if
  11488. * this is the last of the Google layers for the given map.
  11489. */
  11490. removeGMapElements: function() {
  11491. var cache = OpenLayers.Layer.Google.cache[this.map.id];
  11492. if (cache) {
  11493. // remove shared elements from dom
  11494. var container = this.mapObject && this.getMapContainer();
  11495. if (container && container.parentNode) {
  11496. container.parentNode.removeChild(container);
  11497. }
  11498. var termsOfUse = cache.termsOfUse;
  11499. if (termsOfUse && termsOfUse.parentNode) {
  11500. termsOfUse.parentNode.removeChild(termsOfUse);
  11501. }
  11502. var poweredBy = cache.poweredBy;
  11503. if (poweredBy && poweredBy.parentNode) {
  11504. poweredBy.parentNode.removeChild(poweredBy);
  11505. }
  11506. }
  11507. },
  11508. /**
  11509. * APIMethod: removeMap
  11510. * On being removed from the map, also remove termsOfUse and poweredBy divs
  11511. *
  11512. * Parameters:
  11513. * map - {<OpenLayers.Map>}
  11514. */
  11515. removeMap: function(map) {
  11516. // hide layer before removing
  11517. if (this.visibility && this.mapObject) {
  11518. this.setGMapVisibility(false);
  11519. }
  11520. // check to see if last Google layer in this map
  11521. var cache = OpenLayers.Layer.Google.cache[map.id];
  11522. if (cache) {
  11523. if (cache.count <= 1) {
  11524. this.removeGMapElements();
  11525. delete OpenLayers.Layer.Google.cache[map.id];
  11526. } else {
  11527. // decrement the layer count
  11528. --cache.count;
  11529. }
  11530. }
  11531. // remove references to gmap elements
  11532. delete this.termsOfUse;
  11533. delete this.poweredBy;
  11534. delete this.mapObject;
  11535. delete this.dragObject;
  11536. OpenLayers.Layer.EventPane.prototype.removeMap.apply(this, arguments);
  11537. },
  11538. //
  11539. // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
  11540. //
  11541. /**
  11542. * APIMethod: getOLBoundsFromMapObjectBounds
  11543. *
  11544. * Parameters:
  11545. * moBounds - {Object}
  11546. *
  11547. * Returns:
  11548. * {<OpenLayers.Bounds>} An <OpenLayers.Bounds>, translated from the
  11549. * passed-in MapObject Bounds.
  11550. * Returns null if null value is passed in.
  11551. */
  11552. getOLBoundsFromMapObjectBounds: function(moBounds) {
  11553. var olBounds = null;
  11554. if (moBounds != null) {
  11555. var sw = moBounds.getSouthWest();
  11556. var ne = moBounds.getNorthEast();
  11557. if (this.sphericalMercator) {
  11558. sw = this.forwardMercator(sw.lng(), sw.lat());
  11559. ne = this.forwardMercator(ne.lng(), ne.lat());
  11560. } else {
  11561. sw = new OpenLayers.LonLat(sw.lng(), sw.lat());
  11562. ne = new OpenLayers.LonLat(ne.lng(), ne.lat());
  11563. }
  11564. olBounds = new OpenLayers.Bounds(sw.lon,
  11565. sw.lat,
  11566. ne.lon,
  11567. ne.lat );
  11568. }
  11569. return olBounds;
  11570. },
  11571. /**
  11572. * APIMethod: getWarningHTML
  11573. *
  11574. * Returns:
  11575. * {String} String with information on why layer is broken, how to get
  11576. * it working.
  11577. */
  11578. getWarningHTML:function() {
  11579. return OpenLayers.i18n("googleWarning");
  11580. },
  11581. /************************************
  11582. * *
  11583. * MapObject Interface Controls *
  11584. * *
  11585. ************************************/
  11586. // Get&Set Center, Zoom
  11587. /**
  11588. * APIMethod: getMapObjectCenter
  11589. *
  11590. * Returns:
  11591. * {Object} The mapObject's current center in Map Object format
  11592. */
  11593. getMapObjectCenter: function() {
  11594. return this.mapObject.getCenter();
  11595. },
  11596. /**
  11597. * APIMethod: getMapObjectZoom
  11598. *
  11599. * Returns:
  11600. * {Integer} The mapObject's current zoom, in Map Object format
  11601. */
  11602. getMapObjectZoom: function() {
  11603. return this.mapObject.getZoom();
  11604. },
  11605. /************************************
  11606. * *
  11607. * MapObject Primitives *
  11608. * *
  11609. ************************************/
  11610. // LonLat
  11611. /**
  11612. * APIMethod: getLongitudeFromMapObjectLonLat
  11613. *
  11614. * Parameters:
  11615. * moLonLat - {Object} MapObject LonLat format
  11616. *
  11617. * Returns:
  11618. * {Float} Longitude of the given MapObject LonLat
  11619. */
  11620. getLongitudeFromMapObjectLonLat: function(moLonLat) {
  11621. return this.sphericalMercator ?
  11622. this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lon :
  11623. moLonLat.lng();
  11624. },
  11625. /**
  11626. * APIMethod: getLatitudeFromMapObjectLonLat
  11627. *
  11628. * Parameters:
  11629. * moLonLat - {Object} MapObject LonLat format
  11630. *
  11631. * Returns:
  11632. * {Float} Latitude of the given MapObject LonLat
  11633. */
  11634. getLatitudeFromMapObjectLonLat: function(moLonLat) {
  11635. var lat = this.sphericalMercator ?
  11636. this.forwardMercator(moLonLat.lng(), moLonLat.lat()).lat :
  11637. moLonLat.lat();
  11638. return lat;
  11639. },
  11640. // Pixel
  11641. /**
  11642. * APIMethod: getXFromMapObjectPixel
  11643. *
  11644. * Parameters:
  11645. * moPixel - {Object} MapObject Pixel format
  11646. *
  11647. * Returns:
  11648. * {Integer} X value of the MapObject Pixel
  11649. */
  11650. getXFromMapObjectPixel: function(moPixel) {
  11651. return moPixel.x;
  11652. },
  11653. /**
  11654. * APIMethod: getYFromMapObjectPixel
  11655. *
  11656. * Parameters:
  11657. * moPixel - {Object} MapObject Pixel format
  11658. *
  11659. * Returns:
  11660. * {Integer} Y value of the MapObject Pixel
  11661. */
  11662. getYFromMapObjectPixel: function(moPixel) {
  11663. return moPixel.y;
  11664. },
  11665. CLASS_NAME: "OpenLayers.Layer.Google"
  11666. });
  11667. /**
  11668. * Property: OpenLayers.Layer.Google.cache
  11669. * {Object} Cache for elements that should only be created once per map.
  11670. */
  11671. OpenLayers.Layer.Google.cache = {};
  11672. /**
  11673. * Constant: OpenLayers.Layer.Google.v2
  11674. *
  11675. * Mixin providing functionality specific to the Google Maps API v2.
  11676. *
  11677. * This API has been deprecated by Google.
  11678. * Developers are encouraged to migrate to v3 of the API; support for this
  11679. * is provided by <OpenLayers.Layer.Google.v3>
  11680. */
  11681. OpenLayers.Layer.Google.v2 = {
  11682. /**
  11683. * Property: termsOfUse
  11684. * {DOMElement} Div for Google's copyright and terms of use link
  11685. */
  11686. termsOfUse: null,
  11687. /**
  11688. * Property: poweredBy
  11689. * {DOMElement} Div for Google's powered by logo and link
  11690. */
  11691. poweredBy: null,
  11692. /**
  11693. * Property: dragObject
  11694. * {GDraggableObject} Since 2.93, Google has exposed the ability to get
  11695. * the maps GDraggableObject. We can now use this for smooth panning
  11696. */
  11697. dragObject: null,
  11698. /**
  11699. * Method: loadMapObject
  11700. * Load the GMap and register appropriate event listeners. If we can't
  11701. * load GMap2, then display a warning message.
  11702. */
  11703. loadMapObject:function() {
  11704. if (!this.type) {
  11705. this.type = G_NORMAL_MAP;
  11706. }
  11707. var mapObject, termsOfUse, poweredBy;
  11708. var cache = OpenLayers.Layer.Google.cache[this.map.id];
  11709. if (cache) {
  11710. // there are already Google layers added to this map
  11711. mapObject = cache.mapObject;
  11712. termsOfUse = cache.termsOfUse;
  11713. poweredBy = cache.poweredBy;
  11714. // increment the layer count
  11715. ++cache.count;
  11716. } else {
  11717. // this is the first Google layer for this map
  11718. var container = this.map.viewPortDiv;
  11719. var div = document.createElement("div");
  11720. div.id = this.map.id + "_GMap2Container";
  11721. div.style.position = "absolute";
  11722. div.style.width = "100%";
  11723. div.style.height = "100%";
  11724. container.appendChild(div);
  11725. // create GMap and shuffle elements
  11726. try {
  11727. mapObject = new GMap2(div);
  11728. // move the ToS and branding stuff up to the container div
  11729. termsOfUse = div.lastChild;
  11730. container.appendChild(termsOfUse);
  11731. termsOfUse.style.zIndex = "1100";
  11732. termsOfUse.style.right = "";
  11733. termsOfUse.style.bottom = "";
  11734. termsOfUse.className = "olLayerGoogleCopyright";
  11735. poweredBy = div.lastChild;
  11736. container.appendChild(poweredBy);
  11737. poweredBy.style.zIndex = "1100";
  11738. poweredBy.style.right = "";
  11739. poweredBy.style.bottom = "";
  11740. poweredBy.className = "olLayerGooglePoweredBy gmnoprint";
  11741. } catch (e) {
  11742. throw(e);
  11743. }
  11744. // cache elements for use by any other google layers added to
  11745. // this same map
  11746. OpenLayers.Layer.Google.cache[this.map.id] = {
  11747. mapObject: mapObject,
  11748. termsOfUse: termsOfUse,
  11749. poweredBy: poweredBy,
  11750. count: 1
  11751. };
  11752. }
  11753. this.mapObject = mapObject;
  11754. this.termsOfUse = termsOfUse;
  11755. this.poweredBy = poweredBy;
  11756. // ensure this layer type is one of the mapObject types
  11757. if (OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),
  11758. this.type) === -1) {
  11759. this.mapObject.addMapType(this.type);
  11760. }
  11761. //since v 2.93 getDragObject is now available.
  11762. if(typeof mapObject.getDragObject == "function") {
  11763. this.dragObject = mapObject.getDragObject();
  11764. } else {
  11765. this.dragPanMapObject = null;
  11766. }
  11767. if(this.isBaseLayer === false) {
  11768. this.setGMapVisibility(this.div.style.display !== "none");
  11769. }
  11770. },
  11771. /**
  11772. * APIMethod: onMapResize
  11773. */
  11774. onMapResize: function() {
  11775. // workaround for resizing of invisible or not yet fully loaded layers
  11776. // where GMap2.checkResize() does not work. We need to load the GMap
  11777. // for the old div size, then checkResize(), and then call
  11778. // layer.moveTo() to trigger GMap.setCenter() (which will finish
  11779. // the GMap initialization).
  11780. if(this.visibility && this.mapObject.isLoaded()) {
  11781. this.mapObject.checkResize();
  11782. } else {
  11783. if(!this._resized) {
  11784. var layer = this;
  11785. var handle = GEvent.addListener(this.mapObject, "load", function() {
  11786. GEvent.removeListener(handle);
  11787. delete layer._resized;
  11788. layer.mapObject.checkResize();
  11789. layer.moveTo(layer.map.getCenter(), layer.map.getZoom());
  11790. });
  11791. }
  11792. this._resized = true;
  11793. }
  11794. },
  11795. /**
  11796. * Method: setGMapVisibility
  11797. * Display the GMap container and associated elements.
  11798. *
  11799. * Parameters:
  11800. * visible - {Boolean} Display the GMap elements.
  11801. */
  11802. setGMapVisibility: function(visible) {
  11803. var cache = OpenLayers.Layer.Google.cache[this.map.id];
  11804. if (cache) {
  11805. var container = this.mapObject.getContainer();
  11806. if (visible === true) {
  11807. this.mapObject.setMapType(this.type);
  11808. container.style.display = "";
  11809. this.termsOfUse.style.left = "";
  11810. this.termsOfUse.style.display = "";
  11811. this.poweredBy.style.display = "";
  11812. cache.displayed = this.id;
  11813. } else {
  11814. if (cache.displayed === this.id) {
  11815. delete cache.displayed;
  11816. }
  11817. if (!cache.displayed) {
  11818. container.style.display = "none";
  11819. this.termsOfUse.style.display = "none";
  11820. // move ToU far to the left in addition to setting display
  11821. // to "none", because at the end of the GMap2 load
  11822. // sequence, display: none will be unset and ToU would be
  11823. // visible after loading a map with a google layer that is
  11824. // initially hidden.
  11825. this.termsOfUse.style.left = "-9999px";
  11826. this.poweredBy.style.display = "none";
  11827. }
  11828. }
  11829. }
  11830. },
  11831. /**
  11832. * Method: getMapContainer
  11833. *
  11834. * Returns:
  11835. * {DOMElement} the GMap container's div
  11836. */
  11837. getMapContainer: function() {
  11838. return this.mapObject.getContainer();
  11839. },
  11840. //
  11841. // TRANSLATION: MapObject Bounds <-> OpenLayers.Bounds
  11842. //
  11843. /**
  11844. * APIMethod: getMapObjectBoundsFromOLBounds
  11845. *
  11846. * Parameters:
  11847. * olBounds - {<OpenLayers.Bounds>}
  11848. *
  11849. * Returns:
  11850. * {Object} A MapObject Bounds, translated from olBounds
  11851. * Returns null if null value is passed in
  11852. */
  11853. getMapObjectBoundsFromOLBounds: function(olBounds) {
  11854. var moBounds = null;
  11855. if (olBounds != null) {
  11856. var sw = this.sphericalMercator ?
  11857. this.inverseMercator(olBounds.bottom, olBounds.left) :
  11858. new OpenLayers.LonLat(olBounds.bottom, olBounds.left);
  11859. var ne = this.sphericalMercator ?
  11860. this.inverseMercator(olBounds.top, olBounds.right) :
  11861. new OpenLayers.LonLat(olBounds.top, olBounds.right);
  11862. moBounds = new GLatLngBounds(new GLatLng(sw.lat, sw.lon),
  11863. new GLatLng(ne.lat, ne.lon));
  11864. }
  11865. return moBounds;
  11866. },
  11867. /************************************
  11868. * *
  11869. * MapObject Interface Controls *
  11870. * *
  11871. ************************************/
  11872. // Get&Set Center, Zoom
  11873. /**
  11874. * APIMethod: setMapObjectCenter
  11875. * Set the mapObject to the specified center and zoom
  11876. *
  11877. * Parameters:
  11878. * center - {Object} MapObject LonLat format
  11879. * zoom - {int} MapObject zoom format
  11880. */
  11881. setMapObjectCenter: function(center, zoom) {
  11882. this.mapObject.setCenter(center, zoom);
  11883. },
  11884. /**
  11885. * APIMethod: dragPanMapObject
  11886. *
  11887. * Parameters:
  11888. * dX - {Integer}
  11889. * dY - {Integer}
  11890. */
  11891. dragPanMapObject: function(dX, dY) {
  11892. this.dragObject.moveBy(new GSize(-dX, dY));
  11893. },
  11894. // LonLat - Pixel Translation
  11895. /**
  11896. * APIMethod: getMapObjectLonLatFromMapObjectPixel
  11897. *
  11898. * Parameters:
  11899. * moPixel - {Object} MapObject Pixel format
  11900. *
  11901. * Returns:
  11902. * {Object} MapObject LonLat translated from MapObject Pixel
  11903. */
  11904. getMapObjectLonLatFromMapObjectPixel: function(moPixel) {
  11905. return this.mapObject.fromContainerPixelToLatLng(moPixel);
  11906. },
  11907. /**
  11908. * APIMethod: getMapObjectPixelFromMapObjectLonLat
  11909. *
  11910. * Parameters:
  11911. * moLonLat - {Object} MapObject LonLat format
  11912. *
  11913. * Returns:
  11914. * {Object} MapObject Pixel transtlated from MapObject LonLat
  11915. */
  11916. getMapObjectPixelFromMapObjectLonLat: function(moLonLat) {
  11917. return this.mapObject.fromLatLngToContainerPixel(moLonLat);
  11918. },
  11919. // Bounds
  11920. /**
  11921. * APIMethod: getMapObjectZoomFromMapObjectBounds
  11922. *
  11923. * Parameters:
  11924. * moBounds - {Object} MapObject Bounds format
  11925. *
  11926. * Returns:
  11927. * {Object} MapObject Zoom for specified MapObject Bounds
  11928. */
  11929. getMapObjectZoomFromMapObjectBounds: function(moBounds) {
  11930. return this.mapObject.getBoundsZoomLevel(moBounds);
  11931. },
  11932. /************************************
  11933. * *
  11934. * MapObject Primitives *
  11935. * *
  11936. ************************************/
  11937. // LonLat
  11938. /**
  11939. * APIMethod: getMapObjectLonLatFromLonLat
  11940. *
  11941. * Parameters:
  11942. * lon - {Float}
  11943. * lat - {Float}
  11944. *
  11945. * Returns:
  11946. * {Object} MapObject LonLat built from lon and lat params
  11947. */
  11948. getMapObjectLonLatFromLonLat: function(lon, lat) {
  11949. var gLatLng;
  11950. if(this.sphericalMercator) {
  11951. var lonlat = this.inverseMercator(lon, lat);
  11952. gLatLng = new GLatLng(lonlat.lat, lonlat.lon);
  11953. } else {
  11954. gLatLng = new GLatLng(lat, lon);
  11955. }
  11956. return gLatLng;
  11957. },
  11958. // Pixel
  11959. /**
  11960. * APIMethod: getMapObjectPixelFromXY
  11961. *
  11962. * Parameters:
  11963. * x - {Integer}
  11964. * y - {Integer}
  11965. *
  11966. * Returns:
  11967. * {Object} MapObject Pixel from x and y parameters
  11968. */
  11969. getMapObjectPixelFromXY: function(x, y) {
  11970. return new GPoint(x, y);
  11971. }
  11972. };
  11973. /* ======================================================================
  11974. OpenLayers/Format/XML.js
  11975. ====================================================================== */
  11976. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  11977. * full list of contributors). Published under the 2-clause BSD license.
  11978. * See license.txt in the OpenLayers distribution or repository for the
  11979. * full text of the license. */
  11980. /**
  11981. * @requires OpenLayers/Format.js
  11982. */
  11983. /**
  11984. * Class: OpenLayers.Format.XML
  11985. * Read and write XML. For cross-browser XML generation, use methods on an
  11986. * instance of the XML format class instead of on <code>document<end>.
  11987. * The DOM creation and traversing methods exposed here all mimic the
  11988. * W3C XML DOM methods. Create a new parser with the
  11989. * <OpenLayers.Format.XML> constructor.
  11990. *
  11991. * Inherits from:
  11992. * - <OpenLayers.Format>
  11993. */
  11994. OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
  11995. /**
  11996. * Property: namespaces
  11997. * {Object} Mapping of namespace aliases to namespace URIs. Properties
  11998. * of this object should not be set individually. Read-only. All
  11999. * XML subclasses should have their own namespaces object. Use
  12000. * <setNamespace> to add or set a namespace alias after construction.
  12001. */
  12002. namespaces: null,
  12003. /**
  12004. * Property: namespaceAlias
  12005. * {Object} Mapping of namespace URI to namespace alias. This object
  12006. * is read-only. Use <setNamespace> to add or set a namespace alias.
  12007. */
  12008. namespaceAlias: null,
  12009. /**
  12010. * Property: defaultPrefix
  12011. * {String} The default namespace alias for creating element nodes.
  12012. */
  12013. defaultPrefix: null,
  12014. /**
  12015. * Property: readers
  12016. * Contains public functions, grouped by namespace prefix, that will
  12017. * be applied when a namespaced node is found matching the function
  12018. * name. The function will be applied in the scope of this parser
  12019. * with two arguments: the node being read and a context object passed
  12020. * from the parent.
  12021. */
  12022. readers: {},
  12023. /**
  12024. * Property: writers
  12025. * As a compliment to the <readers> property, this structure contains public
  12026. * writing functions grouped by namespace alias and named like the
  12027. * node names they produce.
  12028. */
  12029. writers: {},
  12030. /**
  12031. * Property: xmldom
  12032. * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
  12033. * object. It is not intended to be a browser sniffing property.
  12034. * Instead, the xmldom property is used instead of <code>document<end>
  12035. * where namespaced node creation methods are not supported. In all
  12036. * other browsers, this remains null.
  12037. */
  12038. xmldom: null,
  12039. /**
  12040. * Constructor: OpenLayers.Format.XML
  12041. * Construct an XML parser. The parser is used to read and write XML.
  12042. * Reading XML from a string returns a DOM element. Writing XML from
  12043. * a DOM element returns a string.
  12044. *
  12045. * Parameters:
  12046. * options - {Object} Optional object whose properties will be set on
  12047. * the object.
  12048. */
  12049. initialize: function(options) {
  12050. if(window.ActiveXObject) {
  12051. this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
  12052. }
  12053. OpenLayers.Format.prototype.initialize.apply(this, [options]);
  12054. // clone the namespace object and set all namespace aliases
  12055. this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
  12056. this.namespaceAlias = {};
  12057. for(var alias in this.namespaces) {
  12058. this.namespaceAlias[this.namespaces[alias]] = alias;
  12059. }
  12060. },
  12061. /**
  12062. * APIMethod: destroy
  12063. * Clean up.
  12064. */
  12065. destroy: function() {
  12066. this.xmldom = null;
  12067. OpenLayers.Format.prototype.destroy.apply(this, arguments);
  12068. },
  12069. /**
  12070. * Method: setNamespace
  12071. * Set a namespace alias and URI for the format.
  12072. *
  12073. * Parameters:
  12074. * alias - {String} The namespace alias (prefix).
  12075. * uri - {String} The namespace URI.
  12076. */
  12077. setNamespace: function(alias, uri) {
  12078. this.namespaces[alias] = uri;
  12079. this.namespaceAlias[uri] = alias;
  12080. },
  12081. /**
  12082. * APIMethod: read
  12083. * Deserialize a XML string and return a DOM node.
  12084. *
  12085. * Parameters:
  12086. * text - {String} A XML string
  12087. * Returns:
  12088. * {DOMElement} A DOM node
  12089. */
  12090. read: function(text) {
  12091. var index = text.indexOf('<');
  12092. if(index > 0) {
  12093. text = text.substring(index);
  12094. }
  12095. var node = OpenLayers.Util.Try(
  12096. OpenLayers.Function.bind((
  12097. function() {
  12098. var xmldom;
  12099. /**
  12100. * Since we want to be able to call this method on the prototype
  12101. * itself, this.xmldom may not exist even if in IE.
  12102. */
  12103. if(window.ActiveXObject && !this.xmldom) {
  12104. xmldom = new ActiveXObject("Microsoft.XMLDOM");
  12105. } else {
  12106. xmldom = this.xmldom;
  12107. }
  12108. xmldom.loadXML(text);
  12109. return xmldom;
  12110. }
  12111. ), this),
  12112. function() {
  12113. return new DOMParser().parseFromString(text, 'text/xml');
  12114. },
  12115. function() {
  12116. var req = new XMLHttpRequest();
  12117. req.open("GET", "data:" + "text/xml" +
  12118. ";charset=utf-8," + encodeURIComponent(text), false);
  12119. if(req.overrideMimeType) {
  12120. req.overrideMimeType("text/xml");
  12121. }
  12122. req.send(null);
  12123. return req.responseXML;
  12124. }
  12125. );
  12126. if(this.keepData) {
  12127. this.data = node;
  12128. }
  12129. return node;
  12130. },
  12131. /**
  12132. * APIMethod: write
  12133. * Serialize a DOM node into a XML string.
  12134. *
  12135. * Parameters:
  12136. * node - {DOMElement} A DOM node.
  12137. *
  12138. * Returns:
  12139. * {String} The XML string representation of the input node.
  12140. */
  12141. write: function(node) {
  12142. var data;
  12143. if(this.xmldom) {
  12144. data = node.xml;
  12145. } else {
  12146. var serializer = new XMLSerializer();
  12147. if (node.nodeType == 1) {
  12148. // Add nodes to a document before serializing. Everything else
  12149. // is serialized as is. This may need more work. See #1218 .
  12150. var doc = document.implementation.createDocument("", "", null);
  12151. if (doc.importNode) {
  12152. node = doc.importNode(node, true);
  12153. }
  12154. doc.appendChild(node);
  12155. data = serializer.serializeToString(doc);
  12156. } else {
  12157. data = serializer.serializeToString(node);
  12158. }
  12159. }
  12160. return data;
  12161. },
  12162. /**
  12163. * APIMethod: createElementNS
  12164. * Create a new element with namespace. This node can be appended to
  12165. * another node with the standard node.appendChild method. For
  12166. * cross-browser support, this method must be used instead of
  12167. * document.createElementNS.
  12168. *
  12169. * Parameters:
  12170. * uri - {String} Namespace URI for the element.
  12171. * name - {String} The qualified name of the element (prefix:localname).
  12172. *
  12173. * Returns:
  12174. * {Element} A DOM element with namespace.
  12175. */
  12176. createElementNS: function(uri, name) {
  12177. var element;
  12178. if(this.xmldom) {
  12179. if(typeof uri == "string") {
  12180. element = this.xmldom.createNode(1, name, uri);
  12181. } else {
  12182. element = this.xmldom.createNode(1, name, "");
  12183. }
  12184. } else {
  12185. element = document.createElementNS(uri, name);
  12186. }
  12187. return element;
  12188. },
  12189. /**
  12190. * APIMethod: createTextNode
  12191. * Create a text node. This node can be appended to another node with
  12192. * the standard node.appendChild method. For cross-browser support,
  12193. * this method must be used instead of document.createTextNode.
  12194. *
  12195. * Parameters:
  12196. * text - {String} The text of the node.
  12197. *
  12198. * Returns:
  12199. * {DOMElement} A DOM text node.
  12200. */
  12201. createTextNode: function(text) {
  12202. var node;
  12203. if (typeof text !== "string") {
  12204. text = String(text);
  12205. }
  12206. if(this.xmldom) {
  12207. node = this.xmldom.createTextNode(text);
  12208. } else {
  12209. node = document.createTextNode(text);
  12210. }
  12211. return node;
  12212. },
  12213. /**
  12214. * APIMethod: getElementsByTagNameNS
  12215. * Get a list of elements on a node given the namespace URI and local name.
  12216. * To return all nodes in a given namespace, use '*' for the name
  12217. * argument. To return all nodes of a given (local) name, regardless
  12218. * of namespace, use '*' for the uri argument.
  12219. *
  12220. * Parameters:
  12221. * node - {Element} Node on which to search for other nodes.
  12222. * uri - {String} Namespace URI.
  12223. * name - {String} Local name of the tag (without the prefix).
  12224. *
  12225. * Returns:
  12226. * {NodeList} A node list or array of elements.
  12227. */
  12228. getElementsByTagNameNS: function(node, uri, name) {
  12229. var elements = [];
  12230. if(node.getElementsByTagNameNS) {
  12231. elements = node.getElementsByTagNameNS(uri, name);
  12232. } else {
  12233. // brute force method
  12234. var allNodes = node.getElementsByTagName("*");
  12235. var potentialNode, fullName;
  12236. for(var i=0, len=allNodes.length; i<len; ++i) {
  12237. potentialNode = allNodes[i];
  12238. fullName = (potentialNode.prefix) ?
  12239. (potentialNode.prefix + ":" + name) : name;
  12240. if((name == "*") || (fullName == potentialNode.nodeName)) {
  12241. if((uri == "*") || (uri == potentialNode.namespaceURI)) {
  12242. elements.push(potentialNode);
  12243. }
  12244. }
  12245. }
  12246. }
  12247. return elements;
  12248. },
  12249. /**
  12250. * APIMethod: getAttributeNodeNS
  12251. * Get an attribute node given the namespace URI and local name.
  12252. *
  12253. * Parameters:
  12254. * node - {Element} Node on which to search for attribute nodes.
  12255. * uri - {String} Namespace URI.
  12256. * name - {String} Local name of the attribute (without the prefix).
  12257. *
  12258. * Returns:
  12259. * {DOMElement} An attribute node or null if none found.
  12260. */
  12261. getAttributeNodeNS: function(node, uri, name) {
  12262. var attributeNode = null;
  12263. if(node.getAttributeNodeNS) {
  12264. attributeNode = node.getAttributeNodeNS(uri, name);
  12265. } else {
  12266. var attributes = node.attributes;
  12267. var potentialNode, fullName;
  12268. for(var i=0, len=attributes.length; i<len; ++i) {
  12269. potentialNode = attributes[i];
  12270. if(potentialNode.namespaceURI == uri) {
  12271. fullName = (potentialNode.prefix) ?
  12272. (potentialNode.prefix + ":" + name) : name;
  12273. if(fullName == potentialNode.nodeName) {
  12274. attributeNode = potentialNode;
  12275. break;
  12276. }
  12277. }
  12278. }
  12279. }
  12280. return attributeNode;
  12281. },
  12282. /**
  12283. * APIMethod: getAttributeNS
  12284. * Get an attribute value given the namespace URI and local name.
  12285. *
  12286. * Parameters:
  12287. * node - {Element} Node on which to search for an attribute.
  12288. * uri - {String} Namespace URI.
  12289. * name - {String} Local name of the attribute (without the prefix).
  12290. *
  12291. * Returns:
  12292. * {String} An attribute value or and empty string if none found.
  12293. */
  12294. getAttributeNS: function(node, uri, name) {
  12295. var attributeValue = "";
  12296. if(node.getAttributeNS) {
  12297. attributeValue = node.getAttributeNS(uri, name) || "";
  12298. } else {
  12299. var attributeNode = this.getAttributeNodeNS(node, uri, name);
  12300. if(attributeNode) {
  12301. attributeValue = attributeNode.nodeValue;
  12302. }
  12303. }
  12304. return attributeValue;
  12305. },
  12306. /**
  12307. * APIMethod: getChildValue
  12308. * Get the textual value of the node if it exists, or return an
  12309. * optional default string. Returns an empty string if no first child
  12310. * exists and no default value is supplied.
  12311. *
  12312. * Parameters:
  12313. * node - {DOMElement} The element used to look for a first child value.
  12314. * def - {String} Optional string to return in the event that no
  12315. * first child value exists.
  12316. *
  12317. * Returns:
  12318. * {String} The value of the first child of the given node.
  12319. */
  12320. getChildValue: function(node, def) {
  12321. var value = def || "";
  12322. if(node) {
  12323. for(var child=node.firstChild; child; child=child.nextSibling) {
  12324. switch(child.nodeType) {
  12325. case 3: // text node
  12326. case 4: // cdata section
  12327. value += child.nodeValue;
  12328. }
  12329. }
  12330. }
  12331. return value;
  12332. },
  12333. /**
  12334. * APIMethod: isSimpleContent
  12335. * Test if the given node has only simple content (i.e. no child element
  12336. * nodes).
  12337. *
  12338. * Parameters:
  12339. * node - {DOMElement} An element node.
  12340. *
  12341. * Returns:
  12342. * {Boolean} The node has no child element nodes (nodes of type 1).
  12343. */
  12344. isSimpleContent: function(node) {
  12345. var simple = true;
  12346. for(var child=node.firstChild; child; child=child.nextSibling) {
  12347. if(child.nodeType === 1) {
  12348. simple = false;
  12349. break;
  12350. }
  12351. }
  12352. return simple;
  12353. },
  12354. /**
  12355. * APIMethod: contentType
  12356. * Determine the content type for a given node.
  12357. *
  12358. * Parameters:
  12359. * node - {DOMElement}
  12360. *
  12361. * Returns:
  12362. * {Integer} One of OpenLayers.Format.XML.CONTENT_TYPE.{EMPTY,SIMPLE,COMPLEX,MIXED}
  12363. * if the node has no, simple, complex, or mixed content.
  12364. */
  12365. contentType: function(node) {
  12366. var simple = false,
  12367. complex = false;
  12368. var type = OpenLayers.Format.XML.CONTENT_TYPE.EMPTY;
  12369. for(var child=node.firstChild; child; child=child.nextSibling) {
  12370. switch(child.nodeType) {
  12371. case 1: // element
  12372. complex = true;
  12373. break;
  12374. case 8: // comment
  12375. break;
  12376. default:
  12377. simple = true;
  12378. }
  12379. if(complex && simple) {
  12380. break;
  12381. }
  12382. }
  12383. if(complex && simple) {
  12384. type = OpenLayers.Format.XML.CONTENT_TYPE.MIXED;
  12385. } else if(complex) {
  12386. return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;
  12387. } else if(simple) {
  12388. return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE;
  12389. }
  12390. return type;
  12391. },
  12392. /**
  12393. * APIMethod: hasAttributeNS
  12394. * Determine whether a node has a particular attribute matching the given
  12395. * name and namespace.
  12396. *
  12397. * Parameters:
  12398. * node - {Element} Node on which to search for an attribute.
  12399. * uri - {String} Namespace URI.
  12400. * name - {String} Local name of the attribute (without the prefix).
  12401. *
  12402. * Returns:
  12403. * {Boolean} The node has an attribute matching the name and namespace.
  12404. */
  12405. hasAttributeNS: function(node, uri, name) {
  12406. var found = false;
  12407. if(node.hasAttributeNS) {
  12408. found = node.hasAttributeNS(uri, name);
  12409. } else {
  12410. found = !!this.getAttributeNodeNS(node, uri, name);
  12411. }
  12412. return found;
  12413. },
  12414. /**
  12415. * APIMethod: setAttributeNS
  12416. * Adds a new attribute or changes the value of an attribute with the given
  12417. * namespace and name.
  12418. *
  12419. * Parameters:
  12420. * node - {Element} Element node on which to set the attribute.
  12421. * uri - {String} Namespace URI for the attribute.
  12422. * name - {String} Qualified name (prefix:localname) for the attribute.
  12423. * value - {String} Attribute value.
  12424. */
  12425. setAttributeNS: function(node, uri, name, value) {
  12426. if(node.setAttributeNS) {
  12427. node.setAttributeNS(uri, name, value);
  12428. } else {
  12429. if(this.xmldom) {
  12430. if(uri) {
  12431. var attribute = node.ownerDocument.createNode(
  12432. 2, name, uri
  12433. );
  12434. attribute.nodeValue = value;
  12435. node.setAttributeNode(attribute);
  12436. } else {
  12437. node.setAttribute(name, value);
  12438. }
  12439. } else {
  12440. throw "setAttributeNS not implemented";
  12441. }
  12442. }
  12443. },
  12444. /**
  12445. * Method: createElementNSPlus
  12446. * Shorthand for creating namespaced elements with optional attributes and
  12447. * child text nodes.
  12448. *
  12449. * Parameters:
  12450. * name - {String} The qualified node name.
  12451. * options - {Object} Optional object for node configuration.
  12452. *
  12453. * Valid options:
  12454. * uri - {String} Optional namespace uri for the element - supply a prefix
  12455. * instead if the namespace uri is a property of the format's namespace
  12456. * object.
  12457. * attributes - {Object} Optional attributes to be set using the
  12458. * <setAttributes> method.
  12459. * value - {String} Optional text to be appended as a text node.
  12460. *
  12461. * Returns:
  12462. * {Element} An element node.
  12463. */
  12464. createElementNSPlus: function(name, options) {
  12465. options = options || {};
  12466. // order of prefix preference
  12467. // 1. in the uri option
  12468. // 2. in the prefix option
  12469. // 3. in the qualified name
  12470. // 4. from the defaultPrefix
  12471. var uri = options.uri || this.namespaces[options.prefix];
  12472. if(!uri) {
  12473. var loc = name.indexOf(":");
  12474. uri = this.namespaces[name.substring(0, loc)];
  12475. }
  12476. if(!uri) {
  12477. uri = this.namespaces[this.defaultPrefix];
  12478. }
  12479. var node = this.createElementNS(uri, name);
  12480. if(options.attributes) {
  12481. this.setAttributes(node, options.attributes);
  12482. }
  12483. var value = options.value;
  12484. if(value != null) {
  12485. node.appendChild(this.createTextNode(value));
  12486. }
  12487. return node;
  12488. },
  12489. /**
  12490. * Method: setAttributes
  12491. * Set multiple attributes given key value pairs from an object.
  12492. *
  12493. * Parameters:
  12494. * node - {Element} An element node.
  12495. * obj - {Object || Array} An object whose properties represent attribute
  12496. * names and values represent attribute values. If an attribute name
  12497. * is a qualified name ("prefix:local"), the prefix will be looked up
  12498. * in the parsers {namespaces} object. If the prefix is found,
  12499. * setAttributeNS will be used instead of setAttribute.
  12500. */
  12501. setAttributes: function(node, obj) {
  12502. var value, uri;
  12503. for(var name in obj) {
  12504. if(obj[name] != null && obj[name].toString) {
  12505. value = obj[name].toString();
  12506. // check for qualified attribute name ("prefix:local")
  12507. uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
  12508. this.setAttributeNS(node, uri, name, value);
  12509. }
  12510. }
  12511. },
  12512. /**
  12513. * Method: readNode
  12514. * Shorthand for applying one of the named readers given the node
  12515. * namespace and local name. Readers take two args (node, obj) and
  12516. * generally extend or modify the second.
  12517. *
  12518. * Parameters:
  12519. * node - {DOMElement} The node to be read (required).
  12520. * obj - {Object} The object to be modified (optional).
  12521. *
  12522. * Returns:
  12523. * {Object} The input object, modified (or a new one if none was provided).
  12524. */
  12525. readNode: function(node, obj) {
  12526. if(!obj) {
  12527. obj = {};
  12528. }
  12529. var group = this.readers[node.namespaceURI ? this.namespaceAlias[node.namespaceURI]: this.defaultPrefix];
  12530. if(group) {
  12531. var local = node.localName || node.nodeName.split(":").pop();
  12532. var reader = group[local] || group["*"];
  12533. if(reader) {
  12534. reader.apply(this, [node, obj]);
  12535. }
  12536. }
  12537. return obj;
  12538. },
  12539. /**
  12540. * Method: readChildNodes
  12541. * Shorthand for applying the named readers to all children of a node.
  12542. * For each child of type 1 (element), <readSelf> is called.
  12543. *
  12544. * Parameters:
  12545. * node - {DOMElement} The node to be read (required).
  12546. * obj - {Object} The object to be modified (optional).
  12547. *
  12548. * Returns:
  12549. * {Object} The input object, modified.
  12550. */
  12551. readChildNodes: function(node, obj) {
  12552. if(!obj) {
  12553. obj = {};
  12554. }
  12555. var children = node.childNodes;
  12556. var child;
  12557. for(var i=0, len=children.length; i<len; ++i) {
  12558. child = children[i];
  12559. if(child.nodeType == 1) {
  12560. this.readNode(child, obj);
  12561. }
  12562. }
  12563. return obj;
  12564. },
  12565. /**
  12566. * Method: writeNode
  12567. * Shorthand for applying one of the named writers and appending the
  12568. * results to a node. If a qualified name is not provided for the
  12569. * second argument (and a local name is used instead), the namespace
  12570. * of the parent node will be assumed.
  12571. *
  12572. * Parameters:
  12573. * name - {String} The name of a node to generate. If a qualified name
  12574. * (e.g. "pre:Name") is used, the namespace prefix is assumed to be
  12575. * in the <writers> group. If a local name is used (e.g. "Name") then
  12576. * the namespace of the parent is assumed. If a local name is used
  12577. * and no parent is supplied, then the default namespace is assumed.
  12578. * obj - {Object} Structure containing data for the writer.
  12579. * parent - {DOMElement} Result will be appended to this node. If no parent
  12580. * is supplied, the node will not be appended to anything.
  12581. *
  12582. * Returns:
  12583. * {DOMElement} The child node.
  12584. */
  12585. writeNode: function(name, obj, parent) {
  12586. var prefix, local;
  12587. var split = name.indexOf(":");
  12588. if(split > 0) {
  12589. prefix = name.substring(0, split);
  12590. local = name.substring(split + 1);
  12591. } else {
  12592. if(parent) {
  12593. prefix = this.namespaceAlias[parent.namespaceURI];
  12594. } else {
  12595. prefix = this.defaultPrefix;
  12596. }
  12597. local = name;
  12598. }
  12599. var child = this.writers[prefix][local].apply(this, [obj]);
  12600. if(parent) {
  12601. parent.appendChild(child);
  12602. }
  12603. return child;
  12604. },
  12605. /**
  12606. * APIMethod: getChildEl
  12607. * Get the first child element. Optionally only return the first child
  12608. * if it matches the given name and namespace URI.
  12609. *
  12610. * Parameters:
  12611. * node - {DOMElement} The parent node.
  12612. * name - {String} Optional node name (local) to search for.
  12613. * uri - {String} Optional namespace URI to search for.
  12614. *
  12615. * Returns:
  12616. * {DOMElement} The first child. Returns null if no element is found, if
  12617. * something significant besides an element is found, or if the element
  12618. * found does not match the optional name and uri.
  12619. */
  12620. getChildEl: function(node, name, uri) {
  12621. return node && this.getThisOrNextEl(node.firstChild, name, uri);
  12622. },
  12623. /**
  12624. * APIMethod: getNextEl
  12625. * Get the next sibling element. Optionally get the first sibling only
  12626. * if it matches the given local name and namespace URI.
  12627. *
  12628. * Parameters:
  12629. * node - {DOMElement} The node.
  12630. * name - {String} Optional local name of the sibling to search for.
  12631. * uri - {String} Optional namespace URI of the sibling to search for.
  12632. *
  12633. * Returns:
  12634. * {DOMElement} The next sibling element. Returns null if no element is
  12635. * found, something significant besides an element is found, or the
  12636. * found element does not match the optional name and uri.
  12637. */
  12638. getNextEl: function(node, name, uri) {
  12639. return node && this.getThisOrNextEl(node.nextSibling, name, uri);
  12640. },
  12641. /**
  12642. * Method: getThisOrNextEl
  12643. * Return this node or the next element node. Optionally get the first
  12644. * sibling with the given local name or namespace URI.
  12645. *
  12646. * Parameters:
  12647. * node - {DOMElement} The node.
  12648. * name - {String} Optional local name of the sibling to search for.
  12649. * uri - {String} Optional namespace URI of the sibling to search for.
  12650. *
  12651. * Returns:
  12652. * {DOMElement} The next sibling element. Returns null if no element is
  12653. * found, something significant besides an element is found, or the
  12654. * found element does not match the query.
  12655. */
  12656. getThisOrNextEl: function(node, name, uri) {
  12657. outer: for(var sibling=node; sibling; sibling=sibling.nextSibling) {
  12658. switch(sibling.nodeType) {
  12659. case 1: // Element
  12660. if((!name || name === (sibling.localName || sibling.nodeName.split(":").pop())) &&
  12661. (!uri || uri === sibling.namespaceURI)) {
  12662. // matches
  12663. break outer;
  12664. }
  12665. sibling = null;
  12666. break outer;
  12667. case 3: // Text
  12668. if(/^\s*$/.test(sibling.nodeValue)) {
  12669. break;
  12670. }
  12671. case 4: // CDATA
  12672. case 6: // ENTITY_NODE
  12673. case 12: // NOTATION_NODE
  12674. case 10: // DOCUMENT_TYPE_NODE
  12675. case 11: // DOCUMENT_FRAGMENT_NODE
  12676. sibling = null;
  12677. break outer;
  12678. } // ignore comments and processing instructions
  12679. }
  12680. return sibling || null;
  12681. },
  12682. /**
  12683. * APIMethod: lookupNamespaceURI
  12684. * Takes a prefix and returns the namespace URI associated with it on the given
  12685. * node if found (and null if not). Supplying null for the prefix will
  12686. * return the default namespace.
  12687. *
  12688. * For browsers that support it, this calls the native lookupNamesapceURI
  12689. * function. In other browsers, this is an implementation of
  12690. * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
  12691. *
  12692. * For browsers that don't support the attribute.ownerElement property, this
  12693. * method cannot be called on attribute nodes.
  12694. *
  12695. * Parameters:
  12696. * node - {DOMElement} The node from which to start looking.
  12697. * prefix - {String} The prefix to lookup or null to lookup the default namespace.
  12698. *
  12699. * Returns:
  12700. * {String} The namespace URI for the given prefix. Returns null if the prefix
  12701. * cannot be found or the node is the wrong type.
  12702. */
  12703. lookupNamespaceURI: function(node, prefix) {
  12704. var uri = null;
  12705. if(node) {
  12706. if(node.lookupNamespaceURI) {
  12707. uri = node.lookupNamespaceURI(prefix);
  12708. } else {
  12709. outer: switch(node.nodeType) {
  12710. case 1: // ELEMENT_NODE
  12711. if(node.namespaceURI !== null && node.prefix === prefix) {
  12712. uri = node.namespaceURI;
  12713. break outer;
  12714. }
  12715. var len = node.attributes.length;
  12716. if(len) {
  12717. var attr;
  12718. for(var i=0; i<len; ++i) {
  12719. attr = node.attributes[i];
  12720. if(attr.prefix === "xmlns" && attr.name === "xmlns:" + prefix) {
  12721. uri = attr.value || null;
  12722. break outer;
  12723. } else if(attr.name === "xmlns" && prefix === null) {
  12724. uri = attr.value || null;
  12725. break outer;
  12726. }
  12727. }
  12728. }
  12729. uri = this.lookupNamespaceURI(node.parentNode, prefix);
  12730. break outer;
  12731. case 2: // ATTRIBUTE_NODE
  12732. uri = this.lookupNamespaceURI(node.ownerElement, prefix);
  12733. break outer;
  12734. case 9: // DOCUMENT_NODE
  12735. uri = this.lookupNamespaceURI(node.documentElement, prefix);
  12736. break outer;
  12737. case 6: // ENTITY_NODE
  12738. case 12: // NOTATION_NODE
  12739. case 10: // DOCUMENT_TYPE_NODE
  12740. case 11: // DOCUMENT_FRAGMENT_NODE
  12741. break outer;
  12742. default:
  12743. // TEXT_NODE (3), CDATA_SECTION_NODE (4), ENTITY_REFERENCE_NODE (5),
  12744. // PROCESSING_INSTRUCTION_NODE (7), COMMENT_NODE (8)
  12745. uri = this.lookupNamespaceURI(node.parentNode, prefix);
  12746. break outer;
  12747. }
  12748. }
  12749. }
  12750. return uri;
  12751. },
  12752. /**
  12753. * Method: getXMLDoc
  12754. * Get an XML document for nodes that are not supported in HTML (e.g.
  12755. * createCDATASection). On IE, this will either return an existing or
  12756. * create a new <xmldom> on the instance. On other browsers, this will
  12757. * either return an existing or create a new shared document (see
  12758. * <OpenLayers.Format.XML.document>).
  12759. *
  12760. * Returns:
  12761. * {XMLDocument}
  12762. */
  12763. getXMLDoc: function() {
  12764. if (!OpenLayers.Format.XML.document && !this.xmldom) {
  12765. if (document.implementation && document.implementation.createDocument) {
  12766. OpenLayers.Format.XML.document =
  12767. document.implementation.createDocument("", "", null);
  12768. } else if (!this.xmldom && window.ActiveXObject) {
  12769. this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
  12770. }
  12771. }
  12772. return OpenLayers.Format.XML.document || this.xmldom;
  12773. },
  12774. CLASS_NAME: "OpenLayers.Format.XML"
  12775. });
  12776. OpenLayers.Format.XML.CONTENT_TYPE = {EMPTY: 0, SIMPLE: 1, COMPLEX: 2, MIXED: 3};
  12777. /**
  12778. * APIFunction: OpenLayers.Format.XML.lookupNamespaceURI
  12779. * Takes a prefix and returns the namespace URI associated with it on the given
  12780. * node if found (and null if not). Supplying null for the prefix will
  12781. * return the default namespace.
  12782. *
  12783. * For browsers that support it, this calls the native lookupNamesapceURI
  12784. * function. In other browsers, this is an implementation of
  12785. * http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-lookupNamespaceURI.
  12786. *
  12787. * For browsers that don't support the attribute.ownerElement property, this
  12788. * method cannot be called on attribute nodes.
  12789. *
  12790. * Parameters:
  12791. * node - {DOMElement} The node from which to start looking.
  12792. * prefix - {String} The prefix to lookup or null to lookup the default namespace.
  12793. *
  12794. * Returns:
  12795. * {String} The namespace URI for the given prefix. Returns null if the prefix
  12796. * cannot be found or the node is the wrong type.
  12797. */
  12798. OpenLayers.Format.XML.lookupNamespaceURI = OpenLayers.Function.bind(
  12799. OpenLayers.Format.XML.prototype.lookupNamespaceURI,
  12800. OpenLayers.Format.XML.prototype
  12801. );
  12802. /**
  12803. * Property: OpenLayers.Format.XML.document
  12804. * {XMLDocument} XML document to reuse for creating non-HTML compliant nodes,
  12805. * like document.createCDATASection.
  12806. */
  12807. OpenLayers.Format.XML.document = null;
  12808. /* ======================================================================
  12809. OpenLayers/Format/WFST.js
  12810. ====================================================================== */
  12811. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  12812. * full list of contributors). Published under the 2-clause BSD license.
  12813. * See license.txt in the OpenLayers distribution or repository for the
  12814. * full text of the license. */
  12815. /**
  12816. * @requires OpenLayers/Format.js
  12817. */
  12818. /**
  12819. * Function: OpenLayers.Format.WFST
  12820. * Used to create a versioned WFS protocol. Default version is 1.0.0.
  12821. *
  12822. * Returns:
  12823. * {<OpenLayers.Format>} A WFST format of the given version.
  12824. */
  12825. OpenLayers.Format.WFST = function(options) {
  12826. options = OpenLayers.Util.applyDefaults(
  12827. options, OpenLayers.Format.WFST.DEFAULTS
  12828. );
  12829. var cls = OpenLayers.Format.WFST["v"+options.version.replace(/\./g, "_")];
  12830. if(!cls) {
  12831. throw "Unsupported WFST version: " + options.version;
  12832. }
  12833. return new cls(options);
  12834. };
  12835. /**
  12836. * Constant: OpenLayers.Format.WFST.DEFAULTS
  12837. * {Object} Default properties for the WFST format.
  12838. */
  12839. OpenLayers.Format.WFST.DEFAULTS = {
  12840. "version": "1.0.0"
  12841. };
  12842. /* ======================================================================
  12843. OpenLayers/Format/WFST/v1.js
  12844. ====================================================================== */
  12845. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  12846. * full list of contributors). Published under the 2-clause BSD license.
  12847. * See license.txt in the OpenLayers distribution or repository for the
  12848. * full text of the license. */
  12849. /**
  12850. * @requires OpenLayers/Format/XML.js
  12851. * @requires OpenLayers/Format/WFST.js
  12852. */
  12853. /**
  12854. * Class: OpenLayers.Format.WFST.v1
  12855. * Superclass for WFST parsers.
  12856. *
  12857. * Inherits from:
  12858. * - <OpenLayers.Format.XML>
  12859. */
  12860. OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
  12861. /**
  12862. * Property: namespaces
  12863. * {Object} Mapping of namespace aliases to namespace URIs.
  12864. */
  12865. namespaces: {
  12866. xlink: "http://www.w3.org/1999/xlink",
  12867. xsi: "http://www.w3.org/2001/XMLSchema-instance",
  12868. wfs: "http://www.opengis.net/wfs",
  12869. gml: "http://www.opengis.net/gml",
  12870. ogc: "http://www.opengis.net/ogc",
  12871. ows: "http://www.opengis.net/ows"
  12872. },
  12873. /**
  12874. * Property: defaultPrefix
  12875. */
  12876. defaultPrefix: "wfs",
  12877. /**
  12878. * Property: version
  12879. * {String} WFS version number.
  12880. */
  12881. version: null,
  12882. /**
  12883. * Property: schemaLocation
  12884. * {String} Schema location for a particular minor version.
  12885. */
  12886. schemaLocations: null,
  12887. /**
  12888. * APIProperty: srsName
  12889. * {String} URI for spatial reference system.
  12890. */
  12891. srsName: null,
  12892. /**
  12893. * APIProperty: extractAttributes
  12894. * {Boolean} Extract attributes from GML. Default is true.
  12895. */
  12896. extractAttributes: true,
  12897. /**
  12898. * APIProperty: xy
  12899. * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
  12900. * Changing is not recommended, a new Format should be instantiated.
  12901. */
  12902. xy: true,
  12903. /**
  12904. * Property: stateName
  12905. * {Object} Maps feature states to node names.
  12906. */
  12907. stateName: null,
  12908. /**
  12909. * Constructor: OpenLayers.Format.WFST.v1
  12910. * Instances of this class are not created directly. Use the
  12911. * <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
  12912. * constructor instead.
  12913. *
  12914. * Parameters:
  12915. * options - {Object} An optional object whose properties will be set on
  12916. * this instance.
  12917. */
  12918. initialize: function(options) {
  12919. // set state name mapping
  12920. this.stateName = {};
  12921. this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
  12922. this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
  12923. this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
  12924. OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  12925. },
  12926. /**
  12927. * Method: getSrsName
  12928. */
  12929. getSrsName: function(feature, options) {
  12930. var srsName = options && options.srsName;
  12931. if(!srsName) {
  12932. if(feature && feature.layer) {
  12933. srsName = feature.layer.projection.getCode();
  12934. } else {
  12935. srsName = this.srsName;
  12936. }
  12937. }
  12938. return srsName;
  12939. },
  12940. /**
  12941. * APIMethod: read
  12942. * Parse the response from a transaction. Because WFS is split into
  12943. * Transaction requests (create, update, and delete) and GetFeature
  12944. * requests (read), this method handles parsing of both types of
  12945. * responses.
  12946. *
  12947. * Parameters:
  12948. * data - {String | Document} The WFST document to read
  12949. * options - {Object} Options for the reader
  12950. *
  12951. * Valid options properties:
  12952. * output - {String} either "features" or "object". The default is
  12953. * "features", which means that the method will return an array of
  12954. * features. If set to "object", an object with a "features" property
  12955. * and other properties read by the parser will be returned.
  12956. *
  12957. * Returns:
  12958. * {Array | Object} Output depending on the output option.
  12959. */
  12960. read: function(data, options) {
  12961. options = options || {};
  12962. OpenLayers.Util.applyDefaults(options, {
  12963. output: "features"
  12964. });
  12965. if(typeof data == "string") {
  12966. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  12967. }
  12968. if(data && data.nodeType == 9) {
  12969. data = data.documentElement;
  12970. }
  12971. var obj = {};
  12972. if(data) {
  12973. this.readNode(data, obj, true);
  12974. }
  12975. if(obj.features && options.output === "features") {
  12976. obj = obj.features;
  12977. }
  12978. return obj;
  12979. },
  12980. /**
  12981. * Property: readers
  12982. * Contains public functions, grouped by namespace prefix, that will
  12983. * be applied when a namespaced node is found matching the function
  12984. * name. The function will be applied in the scope of this parser
  12985. * with two arguments: the node being read and a context object passed
  12986. * from the parent.
  12987. */
  12988. readers: {
  12989. "wfs": {
  12990. "FeatureCollection": function(node, obj) {
  12991. obj.features = [];
  12992. this.readChildNodes(node, obj);
  12993. }
  12994. }
  12995. },
  12996. /**
  12997. * Method: write
  12998. * Given an array of features, write a WFS transaction. This assumes
  12999. * the features have a state property that determines the operation
  13000. * type - insert, update, or delete.
  13001. *
  13002. * Parameters:
  13003. * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. See
  13004. * below for a more detailed description of the influence of the
  13005. * feature's *modified* property.
  13006. * options - {Object}
  13007. *
  13008. * feature.modified rules:
  13009. * If a feature has a modified property set, the following checks will be
  13010. * made before a feature's geometry or attribute is included in an Update
  13011. * transaction:
  13012. * - *modified* is not set at all: The geometry and all attributes will be
  13013. * included.
  13014. * - *modified.geometry* is set (null or a geometry): The geometry will be
  13015. * included. If *modified.attributes* is not set, all attributes will
  13016. * be included.
  13017. * - *modified.attributes* is set: Only the attributes set (i.e. to null or
  13018. * a value) in *modified.attributes* will be included.
  13019. * If *modified.geometry* is not set, the geometry will not be included.
  13020. *
  13021. * Valid options include:
  13022. * - *multi* {Boolean} If set to true, geometries will be casted to
  13023. * Multi geometries before writing.
  13024. *
  13025. * Returns:
  13026. * {String} A serialized WFS transaction.
  13027. */
  13028. write: function(features, options) {
  13029. var node = this.writeNode("wfs:Transaction", {
  13030. features:features,
  13031. options: options
  13032. });
  13033. var value = this.schemaLocationAttr();
  13034. if(value) {
  13035. this.setAttributeNS(
  13036. node, this.namespaces["xsi"], "xsi:schemaLocation", value
  13037. );
  13038. }
  13039. return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
  13040. },
  13041. /**
  13042. * Property: writers
  13043. * As a compliment to the readers property, this structure contains public
  13044. * writing functions grouped by namespace alias and named like the
  13045. * node names they produce.
  13046. */
  13047. writers: {
  13048. "wfs": {
  13049. "GetFeature": function(options) {
  13050. var node = this.createElementNSPlus("wfs:GetFeature", {
  13051. attributes: {
  13052. service: "WFS",
  13053. version: this.version,
  13054. handle: options && options.handle,
  13055. outputFormat: options && options.outputFormat,
  13056. maxFeatures: options && options.maxFeatures,
  13057. "xsi:schemaLocation": this.schemaLocationAttr(options)
  13058. }
  13059. });
  13060. if (typeof this.featureType == "string") {
  13061. this.writeNode("Query", options, node);
  13062. } else {
  13063. for (var i=0,len = this.featureType.length; i<len; i++) {
  13064. options.featureType = this.featureType[i];
  13065. this.writeNode("Query", options, node);
  13066. }
  13067. }
  13068. return node;
  13069. },
  13070. "Transaction": function(obj) {
  13071. obj = obj || {};
  13072. var options = obj.options || {};
  13073. var node = this.createElementNSPlus("wfs:Transaction", {
  13074. attributes: {
  13075. service: "WFS",
  13076. version: this.version,
  13077. handle: options.handle
  13078. }
  13079. });
  13080. var i, len;
  13081. var features = obj.features;
  13082. if(features) {
  13083. // temporarily re-assigning geometry types
  13084. if (options.multi === true) {
  13085. OpenLayers.Util.extend(this.geometryTypes, {
  13086. "OpenLayers.Geometry.Point": "MultiPoint",
  13087. "OpenLayers.Geometry.LineString": (this.multiCurve === true) ? "MultiCurve": "MultiLineString",
  13088. "OpenLayers.Geometry.Polygon": (this.multiSurface === true) ? "MultiSurface" : "MultiPolygon"
  13089. });
  13090. }
  13091. var name, feature;
  13092. for(i=0, len=features.length; i<len; ++i) {
  13093. feature = features[i];
  13094. name = this.stateName[feature.state];
  13095. if(name) {
  13096. this.writeNode(name, {
  13097. feature: feature,
  13098. options: options
  13099. }, node);
  13100. }
  13101. }
  13102. // switch back to original geometry types assignment
  13103. if (options.multi === true) {
  13104. this.setGeometryTypes();
  13105. }
  13106. }
  13107. if (options.nativeElements) {
  13108. for (i=0, len=options.nativeElements.length; i<len; ++i) {
  13109. this.writeNode("wfs:Native",
  13110. options.nativeElements[i], node);
  13111. }
  13112. }
  13113. return node;
  13114. },
  13115. "Native": function(nativeElement) {
  13116. var node = this.createElementNSPlus("wfs:Native", {
  13117. attributes: {
  13118. vendorId: nativeElement.vendorId,
  13119. safeToIgnore: nativeElement.safeToIgnore
  13120. },
  13121. value: nativeElement.value
  13122. });
  13123. return node;
  13124. },
  13125. "Insert": function(obj) {
  13126. var feature = obj.feature;
  13127. var options = obj.options;
  13128. var node = this.createElementNSPlus("wfs:Insert", {
  13129. attributes: {
  13130. handle: options && options.handle
  13131. }
  13132. });
  13133. this.srsName = this.getSrsName(feature);
  13134. this.writeNode("feature:_typeName", feature, node);
  13135. return node;
  13136. },
  13137. "Update": function(obj) {
  13138. var feature = obj.feature;
  13139. var options = obj.options;
  13140. var node = this.createElementNSPlus("wfs:Update", {
  13141. attributes: {
  13142. handle: options && options.handle,
  13143. typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
  13144. this.featureType
  13145. }
  13146. });
  13147. if(this.featureNS) {
  13148. node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
  13149. }
  13150. // add in geometry
  13151. var modified = feature.modified;
  13152. if (this.geometryName !== null && (!modified || modified.geometry !== undefined)) {
  13153. this.srsName = this.getSrsName(feature);
  13154. this.writeNode(
  13155. "Property", {name: this.geometryName, value: feature.geometry}, node
  13156. );
  13157. }
  13158. // add in attributes
  13159. for(var key in feature.attributes) {
  13160. if(feature.attributes[key] !== undefined &&
  13161. (!modified || !modified.attributes ||
  13162. (modified.attributes && modified.attributes[key] !== undefined))) {
  13163. this.writeNode(
  13164. "Property", {name: key, value: feature.attributes[key]}, node
  13165. );
  13166. }
  13167. }
  13168. // add feature id filter
  13169. this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
  13170. fids: [feature.fid]
  13171. }), node);
  13172. return node;
  13173. },
  13174. "Property": function(obj) {
  13175. var node = this.createElementNSPlus("wfs:Property");
  13176. this.writeNode("Name", obj.name, node);
  13177. if(obj.value !== null) {
  13178. this.writeNode("Value", obj.value, node);
  13179. }
  13180. return node;
  13181. },
  13182. "Name": function(name) {
  13183. return this.createElementNSPlus("wfs:Name", {value: name});
  13184. },
  13185. "Value": function(obj) {
  13186. var node;
  13187. if(obj instanceof OpenLayers.Geometry) {
  13188. node = this.createElementNSPlus("wfs:Value");
  13189. var geom = this.writeNode("feature:_geometry", obj).firstChild;
  13190. node.appendChild(geom);
  13191. } else {
  13192. node = this.createElementNSPlus("wfs:Value", {value: obj});
  13193. }
  13194. return node;
  13195. },
  13196. "Delete": function(obj) {
  13197. var feature = obj.feature;
  13198. var options = obj.options;
  13199. var node = this.createElementNSPlus("wfs:Delete", {
  13200. attributes: {
  13201. handle: options && options.handle,
  13202. typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
  13203. this.featureType
  13204. }
  13205. });
  13206. if(this.featureNS) {
  13207. node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
  13208. }
  13209. this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
  13210. fids: [feature.fid]
  13211. }), node);
  13212. return node;
  13213. }
  13214. }
  13215. },
  13216. /**
  13217. * Method: schemaLocationAttr
  13218. * Generate the xsi:schemaLocation attribute value.
  13219. *
  13220. * Returns:
  13221. * {String} The xsi:schemaLocation attribute or undefined if none.
  13222. */
  13223. schemaLocationAttr: function(options) {
  13224. options = OpenLayers.Util.extend({
  13225. featurePrefix: this.featurePrefix,
  13226. schema: this.schema
  13227. }, options);
  13228. var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
  13229. if(options.schema) {
  13230. schemaLocations[options.featurePrefix] = options.schema;
  13231. }
  13232. var parts = [];
  13233. var uri;
  13234. for(var key in schemaLocations) {
  13235. uri = this.namespaces[key];
  13236. if(uri) {
  13237. parts.push(uri + " " + schemaLocations[key]);
  13238. }
  13239. }
  13240. var value = parts.join(" ") || undefined;
  13241. return value;
  13242. },
  13243. /**
  13244. * Method: setFilterProperty
  13245. * Set the property of each spatial filter.
  13246. *
  13247. * Parameters:
  13248. * filter - {<OpenLayers.Filter>}
  13249. */
  13250. setFilterProperty: function(filter) {
  13251. if(filter.filters) {
  13252. for(var i=0, len=filter.filters.length; i<len; ++i) {
  13253. OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this, filter.filters[i]);
  13254. }
  13255. } else {
  13256. if(filter instanceof OpenLayers.Filter.Spatial && !filter.property) {
  13257. // got a spatial filter without property, so set it
  13258. filter.property = this.geometryName;
  13259. }
  13260. }
  13261. },
  13262. CLASS_NAME: "OpenLayers.Format.WFST.v1"
  13263. });
  13264. /* ======================================================================
  13265. OpenLayers/Format/OGCExceptionReport.js
  13266. ====================================================================== */
  13267. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  13268. * full list of contributors). Published under the 2-clause BSD license.
  13269. * See license.txt in the OpenLayers distribution or repository for the
  13270. * full text of the license. */
  13271. /**
  13272. * @requires OpenLayers/Format/XML.js
  13273. */
  13274. /**
  13275. * Class: OpenLayers.Format.OGCExceptionReport
  13276. * Class to read exception reports for various OGC services and versions.
  13277. *
  13278. * Inherits from:
  13279. * - <OpenLayers.Format.XML>
  13280. */
  13281. OpenLayers.Format.OGCExceptionReport = OpenLayers.Class(OpenLayers.Format.XML, {
  13282. /**
  13283. * Property: namespaces
  13284. * {Object} Mapping of namespace aliases to namespace URIs.
  13285. */
  13286. namespaces: {
  13287. ogc: "http://www.opengis.net/ogc"
  13288. },
  13289. /**
  13290. * Property: regExes
  13291. * Compiled regular expressions for manipulating strings.
  13292. */
  13293. regExes: {
  13294. trimSpace: (/^\s*|\s*$/g),
  13295. removeSpace: (/\s*/g),
  13296. splitSpace: (/\s+/),
  13297. trimComma: (/\s*,\s*/g)
  13298. },
  13299. /**
  13300. * Property: defaultPrefix
  13301. */
  13302. defaultPrefix: "ogc",
  13303. /**
  13304. * Constructor: OpenLayers.Format.OGCExceptionReport
  13305. * Create a new parser for OGC exception reports.
  13306. *
  13307. * Parameters:
  13308. * options - {Object} An optional object whose properties will be set on
  13309. * this instance.
  13310. */
  13311. /**
  13312. * APIMethod: read
  13313. * Read OGC exception report data from a string, and return an object with
  13314. * information about the exceptions.
  13315. *
  13316. * Parameters:
  13317. * data - {String} or {DOMElement} data to read/parse.
  13318. *
  13319. * Returns:
  13320. * {Object} Information about the exceptions that occurred.
  13321. */
  13322. read: function(data) {
  13323. var result;
  13324. if(typeof data == "string") {
  13325. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  13326. }
  13327. var root = data.documentElement;
  13328. var exceptionInfo = {exceptionReport: null};
  13329. if (root) {
  13330. this.readChildNodes(data, exceptionInfo);
  13331. if (exceptionInfo.exceptionReport === null) {
  13332. // fall-back to OWSCommon since this is a common output format for exceptions
  13333. // we cannot easily use the ows readers directly since they differ for 1.0 and 1.1
  13334. exceptionInfo = new OpenLayers.Format.OWSCommon().read(data);
  13335. }
  13336. }
  13337. return exceptionInfo;
  13338. },
  13339. /**
  13340. * Property: readers
  13341. * Contains public functions, grouped by namespace prefix, that will
  13342. * be applied when a namespaced node is found matching the function
  13343. * name. The function will be applied in the scope of this parser
  13344. * with two arguments: the node being read and a context object passed
  13345. * from the parent.
  13346. */
  13347. readers: {
  13348. "ogc": {
  13349. "ServiceExceptionReport": function(node, obj) {
  13350. obj.exceptionReport = {exceptions: []};
  13351. this.readChildNodes(node, obj.exceptionReport);
  13352. },
  13353. "ServiceException": function(node, exceptionReport) {
  13354. var exception = {
  13355. code: node.getAttribute("code"),
  13356. locator: node.getAttribute("locator"),
  13357. text: this.getChildValue(node)
  13358. };
  13359. exceptionReport.exceptions.push(exception);
  13360. }
  13361. }
  13362. },
  13363. CLASS_NAME: "OpenLayers.Format.OGCExceptionReport"
  13364. });
  13365. /* ======================================================================
  13366. OpenLayers/Format/XML/VersionedOGC.js
  13367. ====================================================================== */
  13368. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  13369. * full list of contributors). Published under the 2-clause BSD license.
  13370. * See license.txt in the OpenLayers distribution or repository for the
  13371. * full text of the license. */
  13372. /**
  13373. * @requires OpenLayers/Format/XML.js
  13374. * @requires OpenLayers/Format/OGCExceptionReport.js
  13375. */
  13376. /**
  13377. * Class: OpenLayers.Format.XML.VersionedOGC
  13378. * Base class for versioned formats, i.e. a format which supports multiple
  13379. * versions.
  13380. *
  13381. * Inherits from:
  13382. * - <OpenLayers.Format.XML>
  13383. */
  13384. OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, {
  13385. /**
  13386. * APIProperty: defaultVersion
  13387. * {String} Version number to assume if none found.
  13388. */
  13389. defaultVersion: null,
  13390. /**
  13391. * APIProperty: version
  13392. * {String} Specify a version string if one is known.
  13393. */
  13394. version: null,
  13395. /**
  13396. * APIProperty: profile
  13397. * {String} If provided, use a custom profile.
  13398. */
  13399. profile: null,
  13400. /**
  13401. * APIProperty: errorProperty
  13402. * {String} Which property of the returned object to check for in order to
  13403. * determine whether or not parsing has failed. In the case that the
  13404. * errorProperty is undefined on the returned object, the document will be
  13405. * run through an OGCExceptionReport parser.
  13406. */
  13407. errorProperty: null,
  13408. /**
  13409. * Property: name
  13410. * {String} The name of this parser, this is the part of the CLASS_NAME
  13411. * except for "OpenLayers.Format."
  13412. */
  13413. name: null,
  13414. /**
  13415. * APIProperty: stringifyOutput
  13416. * {Boolean} If true, write will return a string otherwise a DOMElement.
  13417. * Default is false.
  13418. */
  13419. stringifyOutput: false,
  13420. /**
  13421. * Property: parser
  13422. * {Object} Instance of the versioned parser. Cached for multiple read and
  13423. * write calls of the same version.
  13424. */
  13425. parser: null,
  13426. /**
  13427. * Constructor: OpenLayers.Format.XML.VersionedOGC.
  13428. * Constructor.
  13429. *
  13430. * Parameters:
  13431. * options - {Object} Optional object whose properties will be set on
  13432. * the object.
  13433. */
  13434. initialize: function(options) {
  13435. OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  13436. var className = this.CLASS_NAME;
  13437. this.name = className.substring(className.lastIndexOf(".")+1);
  13438. },
  13439. /**
  13440. * Method: getVersion
  13441. * Returns the version to use. Subclasses can override this function
  13442. * if a different version detection is needed.
  13443. *
  13444. * Parameters:
  13445. * root - {DOMElement}
  13446. * options - {Object} Optional configuration object.
  13447. *
  13448. * Returns:
  13449. * {String} The version to use.
  13450. */
  13451. getVersion: function(root, options) {
  13452. var version;
  13453. // read
  13454. if (root) {
  13455. version = this.version;
  13456. if(!version) {
  13457. version = root.getAttribute("version");
  13458. if(!version) {
  13459. version = this.defaultVersion;
  13460. }
  13461. }
  13462. } else { // write
  13463. version = (options && options.version) ||
  13464. this.version || this.defaultVersion;
  13465. }
  13466. return version;
  13467. },
  13468. /**
  13469. * Method: getParser
  13470. * Get an instance of the cached parser if available, otherwise create one.
  13471. *
  13472. * Parameters:
  13473. * version - {String}
  13474. *
  13475. * Returns:
  13476. * {<OpenLayers.Format>}
  13477. */
  13478. getParser: function(version) {
  13479. version = version || this.defaultVersion;
  13480. var profile = this.profile ? "_" + this.profile : "";
  13481. if(!this.parser || this.parser.VERSION != version) {
  13482. var format = OpenLayers.Format[this.name][
  13483. "v" + version.replace(/\./g, "_") + profile
  13484. ];
  13485. if(!format) {
  13486. throw "Can't find a " + this.name + " parser for version " +
  13487. version + profile;
  13488. }
  13489. this.parser = new format(this.options);
  13490. }
  13491. return this.parser;
  13492. },
  13493. /**
  13494. * APIMethod: write
  13495. * Write a document.
  13496. *
  13497. * Parameters:
  13498. * obj - {Object} An object representing the document.
  13499. * options - {Object} Optional configuration object.
  13500. *
  13501. * Returns:
  13502. * {String} The document as a string
  13503. */
  13504. write: function(obj, options) {
  13505. var version = this.getVersion(null, options);
  13506. this.parser = this.getParser(version);
  13507. var root = this.parser.write(obj, options);
  13508. if (this.stringifyOutput === false) {
  13509. return root;
  13510. } else {
  13511. return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
  13512. }
  13513. },
  13514. /**
  13515. * APIMethod: read
  13516. * Read a doc and return an object representing the document.
  13517. *
  13518. * Parameters:
  13519. * data - {String | DOMElement} Data to read.
  13520. * options - {Object} Options for the reader.
  13521. *
  13522. * Returns:
  13523. * {Object} An object representing the document.
  13524. */
  13525. read: function(data, options) {
  13526. if(typeof data == "string") {
  13527. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  13528. }
  13529. var root = data.documentElement;
  13530. var version = this.getVersion(root);
  13531. this.parser = this.getParser(version);
  13532. var obj = this.parser.read(data, options);
  13533. if (this.errorProperty !== null && obj[this.errorProperty] === undefined) {
  13534. // an error must have happened, so parse it and report back
  13535. var format = new OpenLayers.Format.OGCExceptionReport();
  13536. obj.error = format.read(data);
  13537. }
  13538. obj.version = version;
  13539. return obj;
  13540. },
  13541. CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC"
  13542. });
  13543. /* ======================================================================
  13544. OpenLayers/Feature.js
  13545. ====================================================================== */
  13546. /* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
  13547. * full list of contributors). Published under the 2-clause BSD license.
  13548. * See license.txt in the OpenLayers distribution or repository for the
  13549. * full text of the license. */
  13550. /**
  13551. * @requires OpenLayers/BaseTypes/Class.js
  13552. * @requires OpenLayers/Util.js
  13553. */
  13554. /**
  13555. * Class: OpenLayers.Feature
  13556. * Features are combinations of geography and attributes. The OpenLayers.Feature
  13557. * class specifically combines a marker and a lonlat.
  13558. */
  13559. OpenLayers.Feature = OpenLayers.Class({
  13560. /**
  13561. * Property: layer
  13562. * {<OpenLayers.Layer>}
  13563. */
  13564. layer: null,
  13565. /**
  13566. * Property: