UNPKG

2.62 MBJavaScriptView Raw
1// OpenLayers. See https://openlayers.org/
2// License: https://raw.githubusercontent.com/openlayers/openlayers/master/LICENSE.md
3// Version: v4.3.2
4;(function (root, factory) {
5 if (typeof exports === "object") {
6 module.exports = factory();
7 } else if (typeof define === "function" && define.amd) {
8 define([], factory);
9 } else {
10 root.ol = factory();
11 }
12}(this, function () {
13 var OPENLAYERS = {};
14 var goog = this.goog = {};
15this.CLOSURE_NO_DEPS = true;
16// Copyright 2006 The Closure Library Authors. All Rights Reserved.
17//
18// Licensed under the Apache License, Version 2.0 (the "License");
19// you may not use this file except in compliance with the License.
20// You may obtain a copy of the License at
21//
22// http://www.apache.org/licenses/LICENSE-2.0
23//
24// Unless required by applicable law or agreed to in writing, software
25// distributed under the License is distributed on an "AS-IS" BASIS,
26// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27// See the License for the specific language governing permissions and
28// limitations under the License.
29
30/**
31 * @fileoverview Bootstrap for the Google JS Library (Closure).
32 *
33 * In uncompiled mode base.js will attempt to load Closure's deps file, unless
34 * the global <code>CLOSURE_NO_DEPS</code> is set to true. This allows projects
35 * to include their own deps file(s) from different locations.
36 *
37 * Avoid including base.js more than once. This is strictly discouraged and not
38 * supported. goog.require(...) won't work properly in that case.
39 *
40 * @provideGoog
41 */
42
43
44/**
45 * @define {boolean} Overridden to true by the compiler.
46 */
47var COMPILED = false;
48
49
50/**
51 * Base namespace for the Closure library. Checks to see goog is already
52 * defined in the current scope before assigning to prevent clobbering if
53 * base.js is loaded more than once.
54 *
55 * @const
56 */
57var goog = goog || {};
58
59
60/**
61 * Reference to the global context. In most cases this will be 'window'.
62 */
63goog.global = this;
64
65
66/**
67 * A hook for overriding the define values in uncompiled mode.
68 *
69 * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before
70 * loading base.js. If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES},
71 * {@code goog.define} will use the value instead of the default value. This
72 * allows flags to be overwritten without compilation (this is normally
73 * accomplished with the compiler's "define" flag).
74 *
75 * Example:
76 * <pre>
77 * var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};
78 * </pre>
79 *
80 * @type {Object<string, (string|number|boolean)>|undefined}
81 */
82goog.global.CLOSURE_UNCOMPILED_DEFINES;
83
84
85/**
86 * A hook for overriding the define values in uncompiled or compiled mode,
87 * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code. In
88 * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence.
89 *
90 * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or
91 * string literals or the compiler will emit an error.
92 *
93 * While any @define value may be set, only those set with goog.define will be
94 * effective for uncompiled code.
95 *
96 * Example:
97 * <pre>
98 * var CLOSURE_DEFINES = {'goog.DEBUG': false} ;
99 * </pre>
100 *
101 * @type {Object<string, (string|number|boolean)>|undefined}
102 */
103goog.global.CLOSURE_DEFINES;
104
105
106/**
107 * Returns true if the specified value is not undefined.
108 *
109 * @param {?} val Variable to test.
110 * @return {boolean} Whether variable is defined.
111 */
112goog.isDef = function(val) {
113 // void 0 always evaluates to undefined and hence we do not need to depend on
114 // the definition of the global variable named 'undefined'.
115 return val !== void 0;
116};
117
118/**
119 * Returns true if the specified value is a string.
120 * @param {?} val Variable to test.
121 * @return {boolean} Whether variable is a string.
122 */
123goog.isString = function(val) {
124 return typeof val == 'string';
125};
126
127
128/**
129 * Returns true if the specified value is a boolean.
130 * @param {?} val Variable to test.
131 * @return {boolean} Whether variable is boolean.
132 */
133goog.isBoolean = function(val) {
134 return typeof val == 'boolean';
135};
136
137
138/**
139 * Returns true if the specified value is a number.
140 * @param {?} val Variable to test.
141 * @return {boolean} Whether variable is a number.
142 */
143goog.isNumber = function(val) {
144 return typeof val == 'number';
145};
146
147
148/**
149 * Builds an object structure for the provided namespace path, ensuring that
150 * names that already exist are not overwritten. For example:
151 * "a.b.c" -> a = {};a.b={};a.b.c={};
152 * Used by goog.provide and goog.exportSymbol.
153 * @param {string} name name of the object that this file defines.
154 * @param {*=} opt_object the object to expose at the end of the path.
155 * @param {Object=} opt_objectToExportTo The object to add the path to; default
156 * is `goog.global`.
157 * @private
158 */
159goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
160 var parts = name.split('.');
161 var cur = opt_objectToExportTo || goog.global;
162
163 // Internet Explorer exhibits strange behavior when throwing errors from
164 // methods externed in this manner. See the testExportSymbolExceptions in
165 // base_test.html for an example.
166 if (!(parts[0] in cur) && cur.execScript) {
167 cur.execScript('var ' + parts[0]);
168 }
169
170 for (var part; parts.length && (part = parts.shift());) {
171 if (!parts.length && goog.isDef(opt_object)) {
172 // last part and we have an object; use it
173 cur[part] = opt_object;
174 } else if (cur[part] && cur[part] !== Object.prototype[part]) {
175 cur = cur[part];
176 } else {
177 cur = cur[part] = {};
178 }
179 }
180};
181
182
183/**
184 * Defines a named value. In uncompiled mode, the value is retrieved from
185 * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and
186 * has the property specified, and otherwise used the defined defaultValue.
187 * When compiled the default can be overridden using the compiler
188 * options or the value set in the CLOSURE_DEFINES object.
189 *
190 * @param {string} name The distinguished name to provide.
191 * @param {string|number|boolean} defaultValue
192 */
193goog.define = function(name, defaultValue) {
194 var value = defaultValue;
195 if (!COMPILED) {
196 if (goog.global.CLOSURE_UNCOMPILED_DEFINES &&
197 // Anti DOM-clobbering runtime check (b/37736576).
198 /** @type {?} */ (goog.global.CLOSURE_UNCOMPILED_DEFINES).nodeType ===
199 undefined &&
200 Object.prototype.hasOwnProperty.call(
201 goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) {
202 value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name];
203 } else if (
204 goog.global.CLOSURE_DEFINES &&
205 // Anti DOM-clobbering runtime check (b/37736576).
206 /** @type {?} */ (goog.global.CLOSURE_DEFINES).nodeType === undefined &&
207 Object.prototype.hasOwnProperty.call(
208 goog.global.CLOSURE_DEFINES, name)) {
209 value = goog.global.CLOSURE_DEFINES[name];
210 }
211 }
212 goog.exportPath_(name, value);
213};
214
215
216/**
217 * @define {boolean} DEBUG is provided as a convenience so that debugging code
218 * that should not be included in a production. It can be easily stripped
219 * by specifying --define goog.DEBUG=false to the Closure Compiler aka
220 * JSCompiler. For example, most toString() methods should be declared inside an
221 * "if (goog.DEBUG)" conditional because they are generally used for debugging
222 * purposes and it is difficult for the JSCompiler to statically determine
223 * whether they are used.
224 */
225goog.define('goog.DEBUG', true);
226
227
228/**
229 * @define {string} LOCALE defines the locale being used for compilation. It is
230 * used to select locale specific data to be compiled in js binary. BUILD rule
231 * can specify this value by "--define goog.LOCALE=<locale_name>" as a compiler
232 * option.
233 *
234 * Take into account that the locale code format is important. You should use
235 * the canonical Unicode format with hyphen as a delimiter. Language must be
236 * lowercase, Language Script - Capitalized, Region - UPPERCASE.
237 * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN.
238 *
239 * See more info about locale codes here:
240 * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers
241 *
242 * For language codes you should use values defined by ISO 693-1. See it here
243 * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from
244 * this rule: the Hebrew language. For legacy reasons the old code (iw) should
245 * be used instead of the new code (he).
246 *
247 */
248goog.define('goog.LOCALE', 'en'); // default to en
249
250
251/**
252 * @define {boolean} Whether this code is running on trusted sites.
253 *
254 * On untrusted sites, several native functions can be defined or overridden by
255 * external libraries like Prototype, Datejs, and JQuery and setting this flag
256 * to false forces closure to use its own implementations when possible.
257 *
258 * If your JavaScript can be loaded by a third party site and you are wary about
259 * relying on non-standard implementations, specify
260 * "--define goog.TRUSTED_SITE=false" to the compiler.
261 */
262goog.define('goog.TRUSTED_SITE', true);
263
264
265/**
266 * @define {boolean} Whether a project is expected to be running in strict mode.
267 *
268 * This define can be used to trigger alternate implementations compatible with
269 * running in EcmaScript Strict mode or warn about unavailable functionality.
270 * @see https://goo.gl/PudQ4y
271 *
272 */
273goog.define('goog.STRICT_MODE_COMPATIBLE', false);
274
275
276/**
277 * @define {boolean} Whether code that calls {@link goog.setTestOnly} should
278 * be disallowed in the compilation unit.
279 */
280goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG);
281
282
283/**
284 * @define {boolean} Whether to use a Chrome app CSP-compliant method for
285 * loading scripts via goog.require. @see appendScriptSrcNode_.
286 */
287goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false);
288
289
290/**
291 * Defines a namespace in Closure.
292 *
293 * A namespace may only be defined once in a codebase. It may be defined using
294 * goog.provide() or goog.module().
295 *
296 * The presence of one or more goog.provide() calls in a file indicates
297 * that the file defines the given objects/namespaces.
298 * Provided symbols must not be null or undefined.
299 *
300 * In addition, goog.provide() creates the object stubs for a namespace
301 * (for example, goog.provide("goog.foo.bar") will create the object
302 * goog.foo.bar if it does not already exist).
303 *
304 * Build tools also scan for provide/require/module statements
305 * to discern dependencies, build dependency files (see deps.js), etc.
306 *
307 * @see goog.require
308 * @see goog.module
309 * @param {string} name Namespace provided by this file in the form
310 * "goog.package.part".
311 */
312goog.provide = function(name) {
313 if (goog.isInModuleLoader_()) {
314 throw Error('goog.provide can not be used within a goog.module.');
315 }
316 if (!COMPILED) {
317 // Ensure that the same namespace isn't provided twice.
318 // A goog.module/goog.provide maps a goog.require to a specific file
319 if (goog.isProvided_(name)) {
320 throw Error('Namespace "' + name + '" already declared.');
321 }
322 }
323
324 goog.constructNamespace_(name);
325};
326
327
328/**
329 * @param {string} name Namespace provided by this file in the form
330 * "goog.package.part".
331 * @param {Object=} opt_obj The object to embed in the namespace.
332 * @private
333 */
334goog.constructNamespace_ = function(name, opt_obj) {
335 if (!COMPILED) {
336 delete goog.implicitNamespaces_[name];
337
338 var namespace = name;
339 while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {
340 if (goog.getObjectByName(namespace)) {
341 break;
342 }
343 goog.implicitNamespaces_[namespace] = true;
344 }
345 }
346
347 goog.exportPath_(name, opt_obj);
348};
349
350
351/**
352 * Module identifier validation regexp.
353 * Note: This is a conservative check, it is very possible to be more lenient,
354 * the primary exclusion here is "/" and "\" and a leading ".", these
355 * restrictions are intended to leave the door open for using goog.require
356 * with relative file paths rather than module identifiers.
357 * @private
358 */
359goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/;
360
361
362/**
363 * Defines a module in Closure.
364 *
365 * Marks that this file must be loaded as a module and claims the namespace.
366 *
367 * A namespace may only be defined once in a codebase. It may be defined using
368 * goog.provide() or goog.module().
369 *
370 * goog.module() has three requirements:
371 * - goog.module may not be used in the same file as goog.provide.
372 * - goog.module must be the first statement in the file.
373 * - only one goog.module is allowed per file.
374 *
375 * When a goog.module annotated file is loaded, it is enclosed in
376 * a strict function closure. This means that:
377 * - any variables declared in a goog.module file are private to the file
378 * (not global), though the compiler is expected to inline the module.
379 * - The code must obey all the rules of "strict" JavaScript.
380 * - the file will be marked as "use strict"
381 *
382 * NOTE: unlike goog.provide, goog.module does not declare any symbols by
383 * itself. If declared symbols are desired, use
384 * goog.module.declareLegacyNamespace().
385 *
386 *
387 * See the public goog.module proposal: http://goo.gl/Va1hin
388 *
389 * @param {string} name Namespace provided by this file in the form
390 * "goog.package.part", is expected but not required.
391 * @return {void}
392 */
393goog.module = function(name) {
394 if (!goog.isString(name) || !name ||
395 name.search(goog.VALID_MODULE_RE_) == -1) {
396 throw Error('Invalid module identifier');
397 }
398 if (!goog.isInModuleLoader_()) {
399 throw Error(
400 'Module ' + name + ' has been loaded incorrectly. Note, ' +
401 'modules cannot be loaded as normal scripts. They require some kind of ' +
402 'pre-processing step. You\'re likely trying to load a module via a ' +
403 'script tag or as a part of a concatenated bundle without rewriting the ' +
404 'module. For more info see: ' +
405 'https://github.com/google/closure-library/wiki/goog.module:-an-ES6-module-like-alternative-to-goog.provide.');
406 }
407 if (goog.moduleLoaderState_.moduleName) {
408 throw Error('goog.module may only be called once per module.');
409 }
410
411 // Store the module name for the loader.
412 goog.moduleLoaderState_.moduleName = name;
413 if (!COMPILED) {
414 // Ensure that the same namespace isn't provided twice.
415 // A goog.module/goog.provide maps a goog.require to a specific file
416 if (goog.isProvided_(name)) {
417 throw Error('Namespace "' + name + '" already declared.');
418 }
419 delete goog.implicitNamespaces_[name];
420 }
421};
422
423
424/**
425 * @param {string} name The module identifier.
426 * @return {?} The module exports for an already loaded module or null.
427 *
428 * Note: This is not an alternative to goog.require, it does not
429 * indicate a hard dependency, instead it is used to indicate
430 * an optional dependency or to access the exports of a module
431 * that has already been loaded.
432 * @suppress {missingProvide}
433 */
434goog.module.get = function(name) {
435 return goog.module.getInternal_(name);
436};
437
438
439/**
440 * @param {string} name The module identifier.
441 * @return {?} The module exports for an already loaded module or null.
442 * @private
443 */
444goog.module.getInternal_ = function(name) {
445 if (!COMPILED) {
446 if (name in goog.loadedModules_) {
447 return goog.loadedModules_[name];
448 } else if (!goog.implicitNamespaces_[name]) {
449 var ns = goog.getObjectByName(name);
450 return ns != null ? ns : null;
451 }
452 }
453 return null;
454};
455
456
457/**
458 * @private {?{moduleName: (string|undefined), declareLegacyNamespace:boolean}}
459 */
460goog.moduleLoaderState_ = null;
461
462
463/**
464 * @private
465 * @return {boolean} Whether a goog.module is currently being initialized.
466 */
467goog.isInModuleLoader_ = function() {
468 return goog.moduleLoaderState_ != null;
469};
470
471
472/**
473 * Provide the module's exports as a globally accessible object under the
474 * module's declared name. This is intended to ease migration to goog.module
475 * for files that have existing usages.
476 * @suppress {missingProvide}
477 */
478goog.module.declareLegacyNamespace = function() {
479 if (!COMPILED && !goog.isInModuleLoader_()) {
480 throw new Error(
481 'goog.module.declareLegacyNamespace must be called from ' +
482 'within a goog.module');
483 }
484 if (!COMPILED && !goog.moduleLoaderState_.moduleName) {
485 throw Error(
486 'goog.module must be called prior to ' +
487 'goog.module.declareLegacyNamespace.');
488 }
489 goog.moduleLoaderState_.declareLegacyNamespace = true;
490};
491
492
493/**
494 * Marks that the current file should only be used for testing, and never for
495 * live code in production.
496 *
497 * In the case of unit tests, the message may optionally be an exact namespace
498 * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra
499 * provide (if not explicitly defined in the code).
500 *
501 * @param {string=} opt_message Optional message to add to the error that's
502 * raised when used in production code.
503 */
504goog.setTestOnly = function(opt_message) {
505 if (goog.DISALLOW_TEST_ONLY_CODE) {
506 opt_message = opt_message || '';
507 throw Error(
508 'Importing test-only code into non-debug environment' +
509 (opt_message ? ': ' + opt_message : '.'));
510 }
511};
512
513
514/**
515 * Forward declares a symbol. This is an indication to the compiler that the
516 * symbol may be used in the source yet is not required and may not be provided
517 * in compilation.
518 *
519 * The most common usage of forward declaration is code that takes a type as a
520 * function parameter but does not need to require it. By forward declaring
521 * instead of requiring, no hard dependency is made, and (if not required
522 * elsewhere) the namespace may never be required and thus, not be pulled
523 * into the JavaScript binary. If it is required elsewhere, it will be type
524 * checked as normal.
525 *
526 * Before using goog.forwardDeclare, please read the documentation at
527 * https://github.com/google/closure-compiler/wiki/Bad-Type-Annotation to
528 * understand the options and tradeoffs when working with forward declarations.
529 *
530 * @param {string} name The namespace to forward declare in the form of
531 * "goog.package.part".
532 */
533goog.forwardDeclare = function(name) {};
534
535
536/**
537 * Forward declare type information. Used to assign types to goog.global
538 * referenced object that would otherwise result in unknown type references
539 * and thus block property disambiguation.
540 */
541goog.forwardDeclare('Document');
542goog.forwardDeclare('HTMLScriptElement');
543goog.forwardDeclare('XMLHttpRequest');
544
545
546if (!COMPILED) {
547 /**
548 * Check if the given name has been goog.provided. This will return false for
549 * names that are available only as implicit namespaces.
550 * @param {string} name name of the object to look for.
551 * @return {boolean} Whether the name has been provided.
552 * @private
553 */
554 goog.isProvided_ = function(name) {
555 return (name in goog.loadedModules_) ||
556 (!goog.implicitNamespaces_[name] &&
557 goog.isDefAndNotNull(goog.getObjectByName(name)));
558 };
559
560 /**
561 * Namespaces implicitly defined by goog.provide. For example,
562 * goog.provide('goog.events.Event') implicitly declares that 'goog' and
563 * 'goog.events' must be namespaces.
564 *
565 * @type {!Object<string, (boolean|undefined)>}
566 * @private
567 */
568 goog.implicitNamespaces_ = {'goog.module': true};
569
570 // NOTE: We add goog.module as an implicit namespace as goog.module is defined
571 // here and because the existing module package has not been moved yet out of
572 // the goog.module namespace. This satisifies both the debug loader and
573 // ahead-of-time dependency management.
574}
575
576
577/**
578 * Returns an object based on its fully qualified external name. The object
579 * is not found if null or undefined. If you are using a compilation pass that
580 * renames property names beware that using this function will not find renamed
581 * properties.
582 *
583 * @param {string} name The fully qualified name.
584 * @param {Object=} opt_obj The object within which to look; default is
585 * |goog.global|.
586 * @return {?} The value (object or primitive) or, if not found, null.
587 */
588goog.getObjectByName = function(name, opt_obj) {
589 var parts = name.split('.');
590 var cur = opt_obj || goog.global;
591 for (var part; part = parts.shift();) {
592 if (goog.isDefAndNotNull(cur[part])) {
593 cur = cur[part];
594 } else {
595 return null;
596 }
597 }
598 return cur;
599};
600
601
602/**
603 * Globalizes a whole namespace, such as goog or goog.lang.
604 *
605 * @param {!Object} obj The namespace to globalize.
606 * @param {Object=} opt_global The object to add the properties to.
607 * @deprecated Properties may be explicitly exported to the global scope, but
608 * this should no longer be done in bulk.
609 */
610goog.globalize = function(obj, opt_global) {
611 var global = opt_global || goog.global;
612 for (var x in obj) {
613 global[x] = obj[x];
614 }
615};
616
617
618/**
619 * Adds a dependency from a file to the files it requires.
620 * @param {string} relPath The path to the js file.
621 * @param {!Array<string>} provides An array of strings with
622 * the names of the objects this file provides.
623 * @param {!Array<string>} requires An array of strings with
624 * the names of the objects this file requires.
625 * @param {boolean|!Object<string>=} opt_loadFlags Parameters indicating
626 * how the file must be loaded. The boolean 'true' is equivalent
627 * to {'module': 'goog'} for backwards-compatibility. Valid properties
628 * and values include {'module': 'goog'} and {'lang': 'es6'}.
629 */
630goog.addDependency = function(relPath, provides, requires, opt_loadFlags) {
631 if (goog.DEPENDENCIES_ENABLED) {
632 var provide, require;
633 var path = relPath.replace(/\\/g, '/');
634 var deps = goog.dependencies_;
635 if (!opt_loadFlags || typeof opt_loadFlags === 'boolean') {
636 opt_loadFlags = opt_loadFlags ? {'module': 'goog'} : {};
637 }
638 for (var i = 0; provide = provides[i]; i++) {
639 deps.nameToPath[provide] = path;
640 deps.loadFlags[path] = opt_loadFlags;
641 }
642 for (var j = 0; require = requires[j]; j++) {
643 if (!(path in deps.requires)) {
644 deps.requires[path] = {};
645 }
646 deps.requires[path][require] = true;
647 }
648 }
649};
650
651
652
653
654// NOTE(nnaze): The debug DOM loader was included in base.js as an original way
655// to do "debug-mode" development. The dependency system can sometimes be
656// confusing, as can the debug DOM loader's asynchronous nature.
657//
658// With the DOM loader, a call to goog.require() is not blocking -- the script
659// will not load until some point after the current script. If a namespace is
660// needed at runtime, it needs to be defined in a previous script, or loaded via
661// require() with its registered dependencies.
662//
663// User-defined namespaces may need their own deps file. For a reference on
664// creating a deps file, see:
665// Externally: https://developers.google.com/closure/library/docs/depswriter
666//
667// Because of legacy clients, the DOM loader can't be easily removed from
668// base.js. Work is being done to make it disableable or replaceable for
669// different environments (DOM-less JavaScript interpreters like Rhino or V8,
670// for example). See bootstrap/ for more information.
671
672
673/**
674 * @define {boolean} Whether to enable the debug loader.
675 *
676 * If enabled, a call to goog.require() will attempt to load the namespace by
677 * appending a script tag to the DOM (if the namespace has been registered).
678 *
679 * If disabled, goog.require() will simply assert that the namespace has been
680 * provided (and depend on the fact that some outside tool correctly ordered
681 * the script).
682 */
683goog.define('goog.ENABLE_DEBUG_LOADER', true);
684
685
686/**
687 * @param {string} msg
688 * @private
689 */
690goog.logToConsole_ = function(msg) {
691 if (goog.global.console) {
692 goog.global.console['error'](msg);
693 }
694};
695
696
697/**
698 * Implements a system for the dynamic resolution of dependencies that works in
699 * parallel with the BUILD system. Note that all calls to goog.require will be
700 * stripped by the compiler.
701 * @see goog.provide
702 * @param {string} name Namespace to include (as was given in goog.provide()) in
703 * the form "goog.package.part".
704 * @return {?} If called within a goog.module file, the associated namespace or
705 * module otherwise null.
706 */
707goog.require = function(name) {
708 // If the object already exists we do not need to do anything.
709 if (!COMPILED) {
710 if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) {
711 goog.maybeProcessDeferredDep_(name);
712 }
713
714 if (goog.isProvided_(name)) {
715 if (goog.isInModuleLoader_()) {
716 return goog.module.getInternal_(name);
717 }
718 } else if (goog.ENABLE_DEBUG_LOADER) {
719 var path = goog.getPathFromDeps_(name);
720 if (path) {
721 goog.writeScripts_(path);
722 } else {
723 var errorMessage = 'goog.require could not find: ' + name;
724 goog.logToConsole_(errorMessage);
725
726 throw Error(errorMessage);
727 }
728 }
729
730 return null;
731 }
732};
733
734
735/**
736 * Path for included scripts.
737 * @type {string}
738 */
739goog.basePath = '';
740
741
742/**
743 * A hook for overriding the base path.
744 * @type {string|undefined}
745 */
746goog.global.CLOSURE_BASE_PATH;
747
748
749/**
750 * Whether to attempt to load Closure's deps file. By default, when uncompiled,
751 * deps files will attempt to be loaded.
752 * @type {boolean|undefined}
753 */
754goog.global.CLOSURE_NO_DEPS;
755
756
757/**
758 * A function to import a single script. This is meant to be overridden when
759 * Closure is being run in non-HTML contexts, such as web workers. It's defined
760 * in the global scope so that it can be set before base.js is loaded, which
761 * allows deps.js to be imported properly.
762 *
763 * The function is passed the script source, which is a relative URI. It should
764 * return true if the script was imported, false otherwise.
765 * @type {(function(string): boolean)|undefined}
766 */
767goog.global.CLOSURE_IMPORT_SCRIPT;
768
769
770/**
771 * Null function used for default values of callbacks, etc.
772 * @return {void} Nothing.
773 */
774goog.nullFunction = function() {};
775
776
777/**
778 * When defining a class Foo with an abstract method bar(), you can do:
779 * Foo.prototype.bar = goog.abstractMethod
780 *
781 * Now if a subclass of Foo fails to override bar(), an error will be thrown
782 * when bar() is invoked.
783 *
784 * @type {!Function}
785 * @throws {Error} when invoked to indicate the method should be overridden.
786 */
787goog.abstractMethod = function() {
788 throw Error('unimplemented abstract method');
789};
790
791
792/**
793 * Adds a {@code getInstance} static method that always returns the same
794 * instance object.
795 * @param {!Function} ctor The constructor for the class to add the static
796 * method to.
797 */
798goog.addSingletonGetter = function(ctor) {
799 // instance_ is immediately set to prevent issues with sealed constructors
800 // such as are encountered when a constructor is returned as the export object
801 // of a goog.module in unoptimized code.
802 ctor.instance_ = undefined;
803 ctor.getInstance = function() {
804 if (ctor.instance_) {
805 return ctor.instance_;
806 }
807 if (goog.DEBUG) {
808 // NOTE: JSCompiler can't optimize away Array#push.
809 goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;
810 }
811 return ctor.instance_ = new ctor;
812 };
813};
814
815
816/**
817 * All singleton classes that have been instantiated, for testing. Don't read
818 * it directly, use the {@code goog.testing.singleton} module. The compiler
819 * removes this variable if unused.
820 * @type {!Array<!Function>}
821 * @private
822 */
823goog.instantiatedSingletons_ = [];
824
825
826/**
827 * @define {boolean} Whether to load goog.modules using {@code eval} when using
828 * the debug loader. This provides a better debugging experience as the
829 * source is unmodified and can be edited using Chrome Workspaces or similar.
830 * However in some environments the use of {@code eval} is banned
831 * so we provide an alternative.
832 */
833goog.define('goog.LOAD_MODULE_USING_EVAL', true);
834
835
836/**
837 * @define {boolean} Whether the exports of goog.modules should be sealed when
838 * possible.
839 */
840goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG);
841
842
843/**
844 * The registry of initialized modules:
845 * the module identifier to module exports map.
846 * @private @const {!Object<string, ?>}
847 */
848goog.loadedModules_ = {};
849
850
851/**
852 * True if goog.dependencies_ is available.
853 * @const {boolean}
854 */
855goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER;
856
857
858/**
859 * @define {string} How to decide whether to transpile. Valid values
860 * are 'always', 'never', and 'detect'. The default ('detect') is to
861 * use feature detection to determine which language levels need
862 * transpilation.
863 */
864// NOTE(user): we could expand this to accept a language level to bypass
865// detection: e.g. goog.TRANSPILE == 'es5' would transpile ES6 files but
866// would leave ES3 and ES5 files alone.
867goog.define('goog.TRANSPILE', 'detect');
868
869
870/**
871 * @define {string} Path to the transpiler. Executing the script at this
872 * path (relative to base.js) should define a function $jscomp.transpile.
873 */
874goog.define('goog.TRANSPILER', 'transpile.js');
875
876
877if (goog.DEPENDENCIES_ENABLED) {
878 /**
879 * This object is used to keep track of dependencies and other data that is
880 * used for loading scripts.
881 * @private
882 * @type {{
883 * loadFlags: !Object<string, !Object<string, string>>,
884 * nameToPath: !Object<string, string>,
885 * requires: !Object<string, !Object<string, boolean>>,
886 * visited: !Object<string, boolean>,
887 * written: !Object<string, boolean>,
888 * deferred: !Object<string, string>
889 * }}
890 */
891 goog.dependencies_ = {
892 loadFlags: {}, // 1 to 1
893
894 nameToPath: {}, // 1 to 1
895
896 requires: {}, // 1 to many
897
898 // Used when resolving dependencies to prevent us from visiting file twice.
899 visited: {},
900
901 written: {}, // Used to keep track of script files we have written.
902
903 deferred: {} // Used to track deferred module evaluations in old IEs
904 };
905
906
907 /**
908 * Tries to detect whether is in the context of an HTML document.
909 * @return {boolean} True if it looks like HTML document.
910 * @private
911 */
912 goog.inHtmlDocument_ = function() {
913 /** @type {Document} */
914 var doc = goog.global.document;
915 return doc != null && 'write' in doc; // XULDocument misses write.
916 };
917
918
919 /**
920 * Tries to detect the base path of base.js script that bootstraps Closure.
921 * @private
922 */
923 goog.findBasePath_ = function() {
924 if (goog.isDef(goog.global.CLOSURE_BASE_PATH) &&
925 // Anti DOM-clobbering runtime check (b/37736576).
926 goog.isString(goog.global.CLOSURE_BASE_PATH)) {
927 goog.basePath = goog.global.CLOSURE_BASE_PATH;
928 return;
929 } else if (!goog.inHtmlDocument_()) {
930 return;
931 }
932 /** @type {Document} */
933 var doc = goog.global.document;
934 // If we have a currentScript available, use it exclusively.
935 var currentScript = doc.currentScript;
936 if (currentScript) {
937 var scripts = [currentScript];
938 } else {
939 var scripts = doc.getElementsByTagName('SCRIPT');
940 }
941 // Search backwards since the current script is in almost all cases the one
942 // that has base.js.
943 for (var i = scripts.length - 1; i >= 0; --i) {
944 var script = /** @type {!HTMLScriptElement} */ (scripts[i]);
945 var src = script.src;
946 var qmark = src.lastIndexOf('?');
947 var l = qmark == -1 ? src.length : qmark;
948 if (src.substr(l - 7, 7) == 'base.js') {
949 goog.basePath = src.substr(0, l - 7);
950 return;
951 }
952 }
953 };
954
955
956 /**
957 * Imports a script if, and only if, that script hasn't already been imported.
958 * (Must be called at execution time)
959 * @param {string} src Script source.
960 * @param {string=} opt_sourceText The optionally source text to evaluate
961 * @private
962 */
963 goog.importScript_ = function(src, opt_sourceText) {
964 var importScript =
965 goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;
966 if (importScript(src, opt_sourceText)) {
967 goog.dependencies_.written[src] = true;
968 }
969 };
970
971
972 /**
973 * Whether the browser is IE9 or earlier, which needs special handling
974 * for deferred modules.
975 * @const @private {boolean}
976 */
977 goog.IS_OLD_IE_ =
978 !!(!goog.global.atob && goog.global.document && goog.global.document.all);
979
980
981 /**
982 * Whether IE9 or earlier is waiting on a dependency. This ensures that
983 * deferred modules that have no non-deferred dependencies actually get
984 * loaded, since if we defer them and then never pull in a non-deferred
985 * script, then `goog.loadQueuedModules_` will never be called. Instead,
986 * if not waiting on anything we simply don't defer in the first place.
987 * @private {boolean}
988 */
989 goog.oldIeWaiting_ = false;
990
991
992 /**
993 * Given a URL initiate retrieval and execution of a script that needs
994 * pre-processing.
995 * @param {string} src Script source URL.
996 * @param {boolean} isModule Whether this is a goog.module.
997 * @param {boolean} needsTranspile Whether this source needs transpilation.
998 * @private
999 */
1000 goog.importProcessedScript_ = function(src, isModule, needsTranspile) {
1001 // In an attempt to keep browsers from timing out loading scripts using
1002 // synchronous XHRs, put each load in its own script block.
1003 var bootstrap = 'goog.retrieveAndExec_("' + src + '", ' + isModule + ', ' +
1004 needsTranspile + ');';
1005
1006 goog.importScript_('', bootstrap);
1007 };
1008
1009
1010 /** @private {!Array<string>} */
1011 goog.queuedModules_ = [];
1012
1013
1014 /**
1015 * Return an appropriate module text. Suitable to insert into
1016 * a script tag (that is unescaped).
1017 * @param {string} srcUrl
1018 * @param {string} scriptText
1019 * @return {string}
1020 * @private
1021 */
1022 goog.wrapModule_ = function(srcUrl, scriptText) {
1023 if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) {
1024 return '' +
1025 'goog.loadModule(function(exports) {' +
1026 '"use strict";' + scriptText +
1027 '\n' + // terminate any trailing single line comment.
1028 ';return exports' +
1029 '});' +
1030 '\n//# sourceURL=' + srcUrl + '\n';
1031 } else {
1032 return '' +
1033 'goog.loadModule(' +
1034 goog.global.JSON.stringify(
1035 scriptText + '\n//# sourceURL=' + srcUrl + '\n') +
1036 ');';
1037 }
1038 };
1039
1040 // On IE9 and earlier, it is necessary to handle
1041 // deferred module loads. In later browsers, the
1042 // code to be evaluated is simply inserted as a script
1043 // block in the correct order. To eval deferred
1044 // code at the right time, we piggy back on goog.require to call
1045 // goog.maybeProcessDeferredDep_.
1046 //
1047 // The goog.requires are used both to bootstrap
1048 // the loading process (when no deps are available) and
1049 // declare that they should be available.
1050 //
1051 // Here we eval the sources, if all the deps are available
1052 // either already eval'd or goog.require'd. This will
1053 // be the case when all the dependencies have already
1054 // been loaded, and the dependent module is loaded.
1055 //
1056 // But this alone isn't sufficient because it is also
1057 // necessary to handle the case where there is no root
1058 // that is not deferred. For that there we register for an event
1059 // and trigger goog.loadQueuedModules_ handle any remaining deferred
1060 // evaluations.
1061
1062 /**
1063 * Handle any remaining deferred goog.module evals.
1064 * @private
1065 */
1066 goog.loadQueuedModules_ = function() {
1067 var count = goog.queuedModules_.length;
1068 if (count > 0) {
1069 var queue = goog.queuedModules_;
1070 goog.queuedModules_ = [];
1071 for (var i = 0; i < count; i++) {
1072 var path = queue[i];
1073 goog.maybeProcessDeferredPath_(path);
1074 }
1075 }
1076 goog.oldIeWaiting_ = false;
1077 };
1078
1079
1080 /**
1081 * Eval the named module if its dependencies are
1082 * available.
1083 * @param {string} name The module to load.
1084 * @private
1085 */
1086 goog.maybeProcessDeferredDep_ = function(name) {
1087 if (goog.isDeferredModule_(name) && goog.allDepsAreAvailable_(name)) {
1088 var path = goog.getPathFromDeps_(name);
1089 goog.maybeProcessDeferredPath_(goog.basePath + path);
1090 }
1091 };
1092
1093 /**
1094 * @param {string} name The module to check.
1095 * @return {boolean} Whether the name represents a
1096 * module whose evaluation has been deferred.
1097 * @private
1098 */
1099 goog.isDeferredModule_ = function(name) {
1100 var path = goog.getPathFromDeps_(name);
1101 var loadFlags = path && goog.dependencies_.loadFlags[path] || {};
1102 var languageLevel = loadFlags['lang'] || 'es3';
1103 if (path && (loadFlags['module'] == 'goog' ||
1104 goog.needsTranspile_(languageLevel))) {
1105 var abspath = goog.basePath + path;
1106 return (abspath) in goog.dependencies_.deferred;
1107 }
1108 return false;
1109 };
1110
1111 /**
1112 * @param {string} name The module to check.
1113 * @return {boolean} Whether the name represents a
1114 * module whose declared dependencies have all been loaded
1115 * (eval'd or a deferred module load)
1116 * @private
1117 */
1118 goog.allDepsAreAvailable_ = function(name) {
1119 var path = goog.getPathFromDeps_(name);
1120 if (path && (path in goog.dependencies_.requires)) {
1121 for (var requireName in goog.dependencies_.requires[path]) {
1122 if (!goog.isProvided_(requireName) &&
1123 !goog.isDeferredModule_(requireName)) {
1124 return false;
1125 }
1126 }
1127 }
1128 return true;
1129 };
1130
1131
1132 /**
1133 * @param {string} abspath
1134 * @private
1135 */
1136 goog.maybeProcessDeferredPath_ = function(abspath) {
1137 if (abspath in goog.dependencies_.deferred) {
1138 var src = goog.dependencies_.deferred[abspath];
1139 delete goog.dependencies_.deferred[abspath];
1140 goog.globalEval(src);
1141 }
1142 };
1143
1144
1145 /**
1146 * Load a goog.module from the provided URL. This is not a general purpose
1147 * code loader and does not support late loading code, that is it should only
1148 * be used during page load. This method exists to support unit tests and
1149 * "debug" loaders that would otherwise have inserted script tags. Under the
1150 * hood this needs to use a synchronous XHR and is not recommeneded for
1151 * production code.
1152 *
1153 * The module's goog.requires must have already been satisified; an exception
1154 * will be thrown if this is not the case. This assumption is that no
1155 * "deps.js" file exists, so there is no way to discover and locate the
1156 * module-to-be-loaded's dependencies and no attempt is made to do so.
1157 *
1158 * There should only be one attempt to load a module. If
1159 * "goog.loadModuleFromUrl" is called for an already loaded module, an
1160 * exception will be throw.
1161 *
1162 * @param {string} url The URL from which to attempt to load the goog.module.
1163 */
1164 goog.loadModuleFromUrl = function(url) {
1165 // Because this executes synchronously, we don't need to do any additional
1166 // bookkeeping. When "goog.loadModule" the namespace will be marked as
1167 // having been provided which is sufficient.
1168 goog.retrieveAndExec_(url, true, false);
1169 };
1170
1171
1172 /**
1173 * Writes a new script pointing to {@code src} directly into the DOM.
1174 *
1175 * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for
1176 * the fallback mechanism.
1177 *
1178 * @param {string} src The script URL.
1179 * @private
1180 */
1181 goog.writeScriptSrcNode_ = function(src) {
1182 goog.global.document.write(
1183 '<script type="text/javascript" src="' + src + '"></' +
1184 'script>');
1185 };
1186
1187
1188 /**
1189 * Appends a new script node to the DOM using a CSP-compliant mechanism. This
1190 * method exists as a fallback for document.write (which is not allowed in a
1191 * strict CSP context, e.g., Chrome apps).
1192 *
1193 * NOTE: This method is not analogous to using document.write to insert a
1194 * <script> tag; specifically, the user agent will execute a script added by
1195 * document.write immediately after the current script block finishes
1196 * executing, whereas the DOM-appended script node will not be executed until
1197 * the entire document is parsed and executed. That is to say, this script is
1198 * added to the end of the script execution queue.
1199 *
1200 * The page must not attempt to call goog.required entities until after the
1201 * document has loaded, e.g., in or after the window.onload callback.
1202 *
1203 * @param {string} src The script URL.
1204 * @private
1205 */
1206 goog.appendScriptSrcNode_ = function(src) {
1207 /** @type {Document} */
1208 var doc = goog.global.document;
1209 var scriptEl =
1210 /** @type {HTMLScriptElement} */ (doc.createElement('script'));
1211 scriptEl.type = 'text/javascript';
1212 scriptEl.src = src;
1213 scriptEl.defer = false;
1214 scriptEl.async = false;
1215 doc.head.appendChild(scriptEl);
1216 };
1217
1218
1219 /**
1220 * The default implementation of the import function. Writes a script tag to
1221 * import the script.
1222 *
1223 * @param {string} src The script url.
1224 * @param {string=} opt_sourceText The optionally source text to evaluate
1225 * @return {boolean} True if the script was imported, false otherwise.
1226 * @private
1227 */
1228 goog.writeScriptTag_ = function(src, opt_sourceText) {
1229 if (goog.inHtmlDocument_()) {
1230 /** @type {!HTMLDocument} */
1231 var doc = goog.global.document;
1232
1233 // If the user tries to require a new symbol after document load,
1234 // something has gone terribly wrong. Doing a document.write would
1235 // wipe out the page. This does not apply to the CSP-compliant method
1236 // of writing script tags.
1237 if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING &&
1238 doc.readyState == 'complete') {
1239 // Certain test frameworks load base.js multiple times, which tries
1240 // to write deps.js each time. If that happens, just fail silently.
1241 // These frameworks wipe the page between each load of base.js, so this
1242 // is OK.
1243 var isDeps = /\bdeps.js$/.test(src);
1244 if (isDeps) {
1245 return false;
1246 } else {
1247 throw Error('Cannot write "' + src + '" after document load');
1248 }
1249 }
1250
1251 if (opt_sourceText === undefined) {
1252 if (!goog.IS_OLD_IE_) {
1253 if (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) {
1254 goog.appendScriptSrcNode_(src);
1255 } else {
1256 goog.writeScriptSrcNode_(src);
1257 }
1258 } else {
1259 goog.oldIeWaiting_ = true;
1260 var state = ' onreadystatechange=\'goog.onScriptLoad_(this, ' +
1261 ++goog.lastNonModuleScriptIndex_ + ')\' ';
1262 doc.write(
1263 '<script type="text/javascript" src="' + src + '"' + state +
1264 '></' +
1265 'script>');
1266 }
1267 } else {
1268 doc.write(
1269 '<script type="text/javascript">' +
1270 goog.protectScriptTag_(opt_sourceText) + '</' +
1271 'script>');
1272 }
1273 return true;
1274 } else {
1275 return false;
1276 }
1277 };
1278
1279 /**
1280 * Rewrites closing script tags in input to avoid ending an enclosing script
1281 * tag.
1282 *
1283 * @param {string} str
1284 * @return {string}
1285 * @private
1286 */
1287 goog.protectScriptTag_ = function(str) {
1288 return str.replace(/<\/(SCRIPT)/ig, '\\x3c/$1');
1289 };
1290
1291 /**
1292 * Determines whether the given language needs to be transpiled.
1293 * @param {string} lang
1294 * @return {boolean}
1295 * @private
1296 */
1297 goog.needsTranspile_ = function(lang) {
1298 if (goog.TRANSPILE == 'always') {
1299 return true;
1300 } else if (goog.TRANSPILE == 'never') {
1301 return false;
1302 } else if (!goog.requiresTranspilation_) {
1303 goog.requiresTranspilation_ = goog.createRequiresTranspilation_();
1304 }
1305 if (lang in goog.requiresTranspilation_) {
1306 return goog.requiresTranspilation_[lang];
1307 } else {
1308 throw new Error('Unknown language mode: ' + lang);
1309 }
1310 };
1311
1312 /** @private {?Object<string, boolean>} */
1313 goog.requiresTranspilation_ = null;
1314
1315
1316 /** @private {number} */
1317 goog.lastNonModuleScriptIndex_ = 0;
1318
1319
1320 /**
1321 * A readystatechange handler for legacy IE
1322 * @param {?} script
1323 * @param {number} scriptIndex
1324 * @return {boolean}
1325 * @private
1326 */
1327 goog.onScriptLoad_ = function(script, scriptIndex) {
1328 // for now load the modules when we reach the last script,
1329 // later allow more inter-mingling.
1330 if (script.readyState == 'complete' &&
1331 goog.lastNonModuleScriptIndex_ == scriptIndex) {
1332 goog.loadQueuedModules_();
1333 }
1334 return true;
1335 };
1336
1337 /**
1338 * Resolves dependencies based on the dependencies added using addDependency
1339 * and calls importScript_ in the correct order.
1340 * @param {string} pathToLoad The path from which to start discovering
1341 * dependencies.
1342 * @private
1343 */
1344 goog.writeScripts_ = function(pathToLoad) {
1345 /** @type {!Array<string>} The scripts we need to write this time. */
1346 var scripts = [];
1347 var seenScript = {};
1348 var deps = goog.dependencies_;
1349
1350 /** @param {string} path */
1351 function visitNode(path) {
1352 if (path in deps.written) {
1353 return;
1354 }
1355
1356 // We have already visited this one. We can get here if we have cyclic
1357 // dependencies.
1358 if (path in deps.visited) {
1359 return;
1360 }
1361
1362 deps.visited[path] = true;
1363
1364 if (path in deps.requires) {
1365 for (var requireName in deps.requires[path]) {
1366 // If the required name is defined, we assume that it was already
1367 // bootstrapped by other means.
1368 if (!goog.isProvided_(requireName)) {
1369 if (requireName in deps.nameToPath) {
1370 visitNode(deps.nameToPath[requireName]);
1371 } else {
1372 throw Error('Undefined nameToPath for ' + requireName);
1373 }
1374 }
1375 }
1376 }
1377
1378 if (!(path in seenScript)) {
1379 seenScript[path] = true;
1380 scripts.push(path);
1381 }
1382 }
1383
1384 visitNode(pathToLoad);
1385
1386 // record that we are going to load all these scripts.
1387 for (var i = 0; i < scripts.length; i++) {
1388 var path = scripts[i];
1389 goog.dependencies_.written[path] = true;
1390 }
1391
1392 // If a module is loaded synchronously then we need to
1393 // clear the current inModuleLoader value, and restore it when we are
1394 // done loading the current "requires".
1395 var moduleState = goog.moduleLoaderState_;
1396 goog.moduleLoaderState_ = null;
1397
1398 for (var i = 0; i < scripts.length; i++) {
1399 var path = scripts[i];
1400 if (path) {
1401 var loadFlags = deps.loadFlags[path] || {};
1402 var languageLevel = loadFlags['lang'] || 'es3';
1403 var needsTranspile = goog.needsTranspile_(languageLevel);
1404 if (loadFlags['module'] == 'goog' || needsTranspile) {
1405 goog.importProcessedScript_(
1406 goog.basePath + path, loadFlags['module'] == 'goog',
1407 needsTranspile);
1408 } else {
1409 goog.importScript_(goog.basePath + path);
1410 }
1411 } else {
1412 goog.moduleLoaderState_ = moduleState;
1413 throw Error('Undefined script input');
1414 }
1415 }
1416
1417 // restore the current "module loading state"
1418 goog.moduleLoaderState_ = moduleState;
1419 };
1420
1421
1422 /**
1423 * Looks at the dependency rules and tries to determine the script file that
1424 * fulfills a particular rule.
1425 * @param {string} rule In the form goog.namespace.Class or project.script.
1426 * @return {?string} Url corresponding to the rule, or null.
1427 * @private
1428 */
1429 goog.getPathFromDeps_ = function(rule) {
1430 if (rule in goog.dependencies_.nameToPath) {
1431 return goog.dependencies_.nameToPath[rule];
1432 } else {
1433 return null;
1434 }
1435 };
1436
1437 goog.findBasePath_();
1438
1439 // Allow projects to manage the deps files themselves.
1440 if (!goog.global.CLOSURE_NO_DEPS) {
1441 goog.importScript_(goog.basePath + 'deps.js');
1442 }
1443}
1444
1445
1446/**
1447 * @package {?boolean}
1448 * Visible for testing.
1449 */
1450goog.hasBadLetScoping = null;
1451
1452
1453/**
1454 * @return {boolean}
1455 * @package Visible for testing.
1456 */
1457goog.useSafari10Workaround = function() {
1458 if (goog.hasBadLetScoping == null) {
1459 var hasBadLetScoping;
1460 try {
1461 hasBadLetScoping = !eval(
1462 '"use strict";' +
1463 'let x = 1; function f() { return typeof x; };' +
1464 'f() == "number";');
1465 } catch (e) {
1466 // Assume that ES6 syntax isn't supported.
1467 hasBadLetScoping = false;
1468 }
1469 goog.hasBadLetScoping = hasBadLetScoping;
1470 }
1471 return goog.hasBadLetScoping;
1472};
1473
1474
1475/**
1476 * @param {string} moduleDef
1477 * @return {string}
1478 * @package Visible for testing.
1479 */
1480goog.workaroundSafari10EvalBug = function(moduleDef) {
1481 return '(function(){' + moduleDef +
1482 '\n' + // Terminate any trailing single line comment.
1483 ';' + // Terminate any trailing expression.
1484 '})();\n';
1485};
1486
1487
1488/**
1489 * @param {function(?):?|string} moduleDef The module definition.
1490 */
1491goog.loadModule = function(moduleDef) {
1492 // NOTE: we allow function definitions to be either in the from
1493 // of a string to eval (which keeps the original source intact) or
1494 // in a eval forbidden environment (CSP) we allow a function definition
1495 // which in its body must call {@code goog.module}, and return the exports
1496 // of the module.
1497 var previousState = goog.moduleLoaderState_;
1498 try {
1499 goog.moduleLoaderState_ = {
1500 moduleName: undefined,
1501 declareLegacyNamespace: false
1502 };
1503 var exports;
1504 if (goog.isFunction(moduleDef)) {
1505 exports = moduleDef.call(undefined, {});
1506 } else if (goog.isString(moduleDef)) {
1507 if (goog.useSafari10Workaround()) {
1508 moduleDef = goog.workaroundSafari10EvalBug(moduleDef);
1509 }
1510
1511 exports = goog.loadModuleFromSource_.call(undefined, moduleDef);
1512 } else {
1513 throw Error('Invalid module definition');
1514 }
1515
1516 var moduleName = goog.moduleLoaderState_.moduleName;
1517 if (!goog.isString(moduleName) || !moduleName) {
1518 throw Error('Invalid module name \"' + moduleName + '\"');
1519 }
1520
1521 // Don't seal legacy namespaces as they may be uses as a parent of
1522 // another namespace
1523 if (goog.moduleLoaderState_.declareLegacyNamespace) {
1524 goog.constructNamespace_(moduleName, exports);
1525 } else if (
1526 goog.SEAL_MODULE_EXPORTS && Object.seal && typeof exports == 'object' &&
1527 exports != null) {
1528 Object.seal(exports);
1529 }
1530
1531 goog.loadedModules_[moduleName] = exports;
1532 } finally {
1533 goog.moduleLoaderState_ = previousState;
1534 }
1535};
1536
1537
1538/**
1539 * @private @const
1540 */
1541goog.loadModuleFromSource_ = /** @type {function(string):?} */ (function() {
1542 // NOTE: we avoid declaring parameters or local variables here to avoid
1543 // masking globals or leaking values into the module definition.
1544 'use strict';
1545 var exports = {};
1546 eval(arguments[0]);
1547 return exports;
1548});
1549
1550
1551/**
1552 * Normalize a file path by removing redundant ".." and extraneous "." file
1553 * path components.
1554 * @param {string} path
1555 * @return {string}
1556 * @private
1557 */
1558goog.normalizePath_ = function(path) {
1559 var components = path.split('/');
1560 var i = 0;
1561 while (i < components.length) {
1562 if (components[i] == '.') {
1563 components.splice(i, 1);
1564 } else if (
1565 i && components[i] == '..' && components[i - 1] &&
1566 components[i - 1] != '..') {
1567 components.splice(--i, 2);
1568 } else {
1569 i++;
1570 }
1571 }
1572 return components.join('/');
1573};
1574
1575
1576/**
1577 * Provides a hook for loading a file when using Closure's goog.require() API
1578 * with goog.modules. In particular this hook is provided to support Node.js.
1579 *
1580 * @type {(function(string):string)|undefined}
1581 */
1582goog.global.CLOSURE_LOAD_FILE_SYNC;
1583
1584
1585/**
1586 * Loads file by synchronous XHR. Should not be used in production environments.
1587 * @param {string} src Source URL.
1588 * @return {?string} File contents, or null if load failed.
1589 * @private
1590 */
1591goog.loadFileSync_ = function(src) {
1592 if (goog.global.CLOSURE_LOAD_FILE_SYNC) {
1593 return goog.global.CLOSURE_LOAD_FILE_SYNC(src);
1594 } else {
1595 try {
1596 /** @type {XMLHttpRequest} */
1597 var xhr = new goog.global['XMLHttpRequest']();
1598 xhr.open('get', src, false);
1599 xhr.send();
1600 // NOTE: Successful http: requests have a status of 200, but successful
1601 // file: requests may have a status of zero. Any other status, or a
1602 // thrown exception (particularly in case of file: requests) indicates
1603 // some sort of error, which we treat as a missing or unavailable file.
1604 return xhr.status == 0 || xhr.status == 200 ? xhr.responseText : null;
1605 } catch (err) {
1606 // No need to rethrow or log, since errors should show up on their own.
1607 return null;
1608 }
1609 }
1610};
1611
1612
1613/**
1614 * Retrieve and execute a script that needs some sort of wrapping.
1615 * @param {string} src Script source URL.
1616 * @param {boolean} isModule Whether to load as a module.
1617 * @param {boolean} needsTranspile Whether to transpile down to ES3.
1618 * @private
1619 */
1620goog.retrieveAndExec_ = function(src, isModule, needsTranspile) {
1621 if (!COMPILED) {
1622 // The full but non-canonicalized URL for later use.
1623 var originalPath = src;
1624 // Canonicalize the path, removing any /./ or /../ since Chrome's debugging
1625 // console doesn't auto-canonicalize XHR loads as it does <script> srcs.
1626 src = goog.normalizePath_(src);
1627
1628 var importScript =
1629 goog.global.CLOSURE_IMPORT_SCRIPT || goog.writeScriptTag_;
1630
1631 var scriptText = goog.loadFileSync_(src);
1632 if (scriptText == null) {
1633 throw new Error('Load of "' + src + '" failed');
1634 }
1635
1636 if (needsTranspile) {
1637 scriptText = goog.transpile_.call(goog.global, scriptText, src);
1638 }
1639
1640 if (isModule) {
1641 scriptText = goog.wrapModule_(src, scriptText);
1642 } else {
1643 scriptText += '\n//# sourceURL=' + src;
1644 }
1645 var isOldIE = goog.IS_OLD_IE_;
1646 if (isOldIE && goog.oldIeWaiting_) {
1647 goog.dependencies_.deferred[originalPath] = scriptText;
1648 goog.queuedModules_.push(originalPath);
1649 } else {
1650 importScript(src, scriptText);
1651 }
1652 }
1653};
1654
1655
1656/**
1657 * Lazily retrieves the transpiler and applies it to the source.
1658 * @param {string} code JS code.
1659 * @param {string} path Path to the code.
1660 * @return {string} The transpiled code.
1661 * @private
1662 */
1663goog.transpile_ = function(code, path) {
1664 var jscomp = goog.global['$jscomp'];
1665 if (!jscomp) {
1666 goog.global['$jscomp'] = jscomp = {};
1667 }
1668 var transpile = jscomp.transpile;
1669 if (!transpile) {
1670 var transpilerPath = goog.basePath + goog.TRANSPILER;
1671 var transpilerCode = goog.loadFileSync_(transpilerPath);
1672 if (transpilerCode) {
1673 // This must be executed synchronously, since by the time we know we
1674 // need it, we're about to load and write the ES6 code synchronously,
1675 // so a normal script-tag load will be too slow.
1676 eval(transpilerCode + '\n//# sourceURL=' + transpilerPath);
1677 // Even though the transpiler is optional, if $gwtExport is found, it's
1678 // a sign the transpiler was loaded and the $jscomp.transpile *should*
1679 // be there.
1680 if (goog.global['$gwtExport'] && goog.global['$gwtExport']['$jscomp'] &&
1681 !goog.global['$gwtExport']['$jscomp']['transpile']) {
1682 throw new Error(
1683 'The transpiler did not properly export the "transpile" ' +
1684 'method. $gwtExport: ' + JSON.stringify(goog.global['$gwtExport']));
1685 }
1686 // transpile.js only exports a single $jscomp function, transpile. We
1687 // grab just that and add it to the existing definition of $jscomp which
1688 // contains the polyfills.
1689 goog.global['$jscomp'].transpile =
1690 goog.global['$gwtExport']['$jscomp']['transpile'];
1691 jscomp = goog.global['$jscomp'];
1692 transpile = jscomp.transpile;
1693 }
1694 }
1695 if (!transpile) {
1696 // The transpiler is an optional component. If it's not available then
1697 // replace it with a pass-through function that simply logs.
1698 var suffix = ' requires transpilation but no transpiler was found.';
1699 transpile = jscomp.transpile = function(code, path) {
1700 // TODO(user): figure out some way to get this error to show up
1701 // in test results, noting that the failure may occur in many
1702 // different ways, including in loadModule() before the test
1703 // runner even comes up.
1704 goog.logToConsole_(path + suffix);
1705 return code;
1706 };
1707 }
1708 // Note: any transpilation errors/warnings will be logged to the console.
1709 return transpile(code, path);
1710};
1711
1712
1713//==============================================================================
1714// Language Enhancements
1715//==============================================================================
1716
1717
1718/**
1719 * This is a "fixed" version of the typeof operator. It differs from the typeof
1720 * operator in such a way that null returns 'null' and arrays return 'array'.
1721 * @param {?} value The value to get the type of.
1722 * @return {string} The name of the type.
1723 */
1724goog.typeOf = function(value) {
1725 var s = typeof value;
1726 if (s == 'object') {
1727 if (value) {
1728 // Check these first, so we can avoid calling Object.prototype.toString if
1729 // possible.
1730 //
1731 // IE improperly marshals typeof across execution contexts, but a
1732 // cross-context object will still return false for "instanceof Object".
1733 if (value instanceof Array) {
1734 return 'array';
1735 } else if (value instanceof Object) {
1736 return s;
1737 }
1738
1739 // HACK: In order to use an Object prototype method on the arbitrary
1740 // value, the compiler requires the value be cast to type Object,
1741 // even though the ECMA spec explicitly allows it.
1742 var className = Object.prototype.toString.call(
1743 /** @type {!Object} */ (value));
1744 // In Firefox 3.6, attempting to access iframe window objects' length
1745 // property throws an NS_ERROR_FAILURE, so we need to special-case it
1746 // here.
1747 if (className == '[object Window]') {
1748 return 'object';
1749 }
1750
1751 // We cannot always use constructor == Array or instanceof Array because
1752 // different frames have different Array objects. In IE6, if the iframe
1753 // where the array was created is destroyed, the array loses its
1754 // prototype. Then dereferencing val.splice here throws an exception, so
1755 // we can't use goog.isFunction. Calling typeof directly returns 'unknown'
1756 // so that will work. In this case, this function will return false and
1757 // most array functions will still work because the array is still
1758 // array-like (supports length and []) even though it has lost its
1759 // prototype.
1760 // Mark Miller noticed that Object.prototype.toString
1761 // allows access to the unforgeable [[Class]] property.
1762 // 15.2.4.2 Object.prototype.toString ( )
1763 // When the toString method is called, the following steps are taken:
1764 // 1. Get the [[Class]] property of this object.
1765 // 2. Compute a string value by concatenating the three strings
1766 // "[object ", Result(1), and "]".
1767 // 3. Return Result(2).
1768 // and this behavior survives the destruction of the execution context.
1769 if ((className == '[object Array]' ||
1770 // In IE all non value types are wrapped as objects across window
1771 // boundaries (not iframe though) so we have to do object detection
1772 // for this edge case.
1773 typeof value.length == 'number' &&
1774 typeof value.splice != 'undefined' &&
1775 typeof value.propertyIsEnumerable != 'undefined' &&
1776 !value.propertyIsEnumerable('splice')
1777
1778 )) {
1779 return 'array';
1780 }
1781 // HACK: There is still an array case that fails.
1782 // function ArrayImpostor() {}
1783 // ArrayImpostor.prototype = [];
1784 // var impostor = new ArrayImpostor;
1785 // this can be fixed by getting rid of the fast path
1786 // (value instanceof Array) and solely relying on
1787 // (value && Object.prototype.toString.vall(value) === '[object Array]')
1788 // but that would require many more function calls and is not warranted
1789 // unless closure code is receiving objects from untrusted sources.
1790
1791 // IE in cross-window calls does not correctly marshal the function type
1792 // (it appears just as an object) so we cannot use just typeof val ==
1793 // 'function'. However, if the object has a call property, it is a
1794 // function.
1795 if ((className == '[object Function]' ||
1796 typeof value.call != 'undefined' &&
1797 typeof value.propertyIsEnumerable != 'undefined' &&
1798 !value.propertyIsEnumerable('call'))) {
1799 return 'function';
1800 }
1801
1802 } else {
1803 return 'null';
1804 }
1805
1806 } else if (s == 'function' && typeof value.call == 'undefined') {
1807 // In Safari typeof nodeList returns 'function', and on Firefox typeof
1808 // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We
1809 // would like to return object for those and we can detect an invalid
1810 // function by making sure that the function object has a call method.
1811 return 'object';
1812 }
1813 return s;
1814};
1815
1816
1817/**
1818 * Returns true if the specified value is null.
1819 * @param {?} val Variable to test.
1820 * @return {boolean} Whether variable is null.
1821 */
1822goog.isNull = function(val) {
1823 return val === null;
1824};
1825
1826
1827/**
1828 * Returns true if the specified value is defined and not null.
1829 * @param {?} val Variable to test.
1830 * @return {boolean} Whether variable is defined and not null.
1831 */
1832goog.isDefAndNotNull = function(val) {
1833 // Note that undefined == null.
1834 return val != null;
1835};
1836
1837
1838/**
1839 * Returns true if the specified value is an array.
1840 * @param {?} val Variable to test.
1841 * @return {boolean} Whether variable is an array.
1842 */
1843goog.isArray = function(val) {
1844 return goog.typeOf(val) == 'array';
1845};
1846
1847
1848/**
1849 * Returns true if the object looks like an array. To qualify as array like
1850 * the value needs to be either a NodeList or an object with a Number length
1851 * property. As a special case, a function value is not array like, because its
1852 * length property is fixed to correspond to the number of expected arguments.
1853 * @param {?} val Variable to test.
1854 * @return {boolean} Whether variable is an array.
1855 */
1856goog.isArrayLike = function(val) {
1857 var type = goog.typeOf(val);
1858 // We do not use goog.isObject here in order to exclude function values.
1859 return type == 'array' || type == 'object' && typeof val.length == 'number';
1860};
1861
1862
1863/**
1864 * Returns true if the object looks like a Date. To qualify as Date-like the
1865 * value needs to be an object and have a getFullYear() function.
1866 * @param {?} val Variable to test.
1867 * @return {boolean} Whether variable is a like a Date.
1868 */
1869goog.isDateLike = function(val) {
1870 return goog.isObject(val) && typeof val.getFullYear == 'function';
1871};
1872
1873
1874/**
1875 * Returns true if the specified value is a function.
1876 * @param {?} val Variable to test.
1877 * @return {boolean} Whether variable is a function.
1878 */
1879goog.isFunction = function(val) {
1880 return goog.typeOf(val) == 'function';
1881};
1882
1883
1884/**
1885 * Returns true if the specified value is an object. This includes arrays and
1886 * functions.
1887 * @param {?} val Variable to test.
1888 * @return {boolean} Whether variable is an object.
1889 */
1890goog.isObject = function(val) {
1891 var type = typeof val;
1892 return type == 'object' && val != null || type == 'function';
1893 // return Object(val) === val also works, but is slower, especially if val is
1894 // not an object.
1895};
1896
1897
1898/**
1899 * Gets a unique ID for an object. This mutates the object so that further calls
1900 * with the same object as a parameter returns the same value. The unique ID is
1901 * guaranteed to be unique across the current session amongst objects that are
1902 * passed into {@code getUid}. There is no guarantee that the ID is unique or
1903 * consistent across sessions. It is unsafe to generate unique ID for function
1904 * prototypes.
1905 *
1906 * @param {Object} obj The object to get the unique ID for.
1907 * @return {number} The unique ID for the object.
1908 */
1909goog.getUid = function(obj) {
1910 // TODO(arv): Make the type stricter, do not accept null.
1911
1912 // In Opera window.hasOwnProperty exists but always returns false so we avoid
1913 // using it. As a consequence the unique ID generated for BaseClass.prototype
1914 // and SubClass.prototype will be the same.
1915 return obj[goog.UID_PROPERTY_] ||
1916 (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_);
1917};
1918
1919
1920/**
1921 * Whether the given object is already assigned a unique ID.
1922 *
1923 * This does not modify the object.
1924 *
1925 * @param {!Object} obj The object to check.
1926 * @return {boolean} Whether there is an assigned unique id for the object.
1927 */
1928goog.hasUid = function(obj) {
1929 return !!obj[goog.UID_PROPERTY_];
1930};
1931
1932
1933/**
1934 * Removes the unique ID from an object. This is useful if the object was
1935 * previously mutated using {@code goog.getUid} in which case the mutation is
1936 * undone.
1937 * @param {Object} obj The object to remove the unique ID field from.
1938 */
1939goog.removeUid = function(obj) {
1940 // TODO(arv): Make the type stricter, do not accept null.
1941
1942 // In IE, DOM nodes are not instances of Object and throw an exception if we
1943 // try to delete. Instead we try to use removeAttribute.
1944 if (obj !== null && 'removeAttribute' in obj) {
1945 obj.removeAttribute(goog.UID_PROPERTY_);
1946 }
1947
1948 try {
1949 delete obj[goog.UID_PROPERTY_];
1950 } catch (ex) {
1951 }
1952};
1953
1954
1955/**
1956 * Name for unique ID property. Initialized in a way to help avoid collisions
1957 * with other closure JavaScript on the same page.
1958 * @type {string}
1959 * @private
1960 */
1961goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0);
1962
1963
1964/**
1965 * Counter for UID.
1966 * @type {number}
1967 * @private
1968 */
1969goog.uidCounter_ = 0;
1970
1971
1972/**
1973 * Adds a hash code field to an object. The hash code is unique for the
1974 * given object.
1975 * @param {Object} obj The object to get the hash code for.
1976 * @return {number} The hash code for the object.
1977 * @deprecated Use goog.getUid instead.
1978 */
1979goog.getHashCode = goog.getUid;
1980
1981
1982/**
1983 * Removes the hash code field from an object.
1984 * @param {Object} obj The object to remove the field from.
1985 * @deprecated Use goog.removeUid instead.
1986 */
1987goog.removeHashCode = goog.removeUid;
1988
1989
1990/**
1991 * Clones a value. The input may be an Object, Array, or basic type. Objects and
1992 * arrays will be cloned recursively.
1993 *
1994 * WARNINGS:
1995 * <code>goog.cloneObject</code> does not detect reference loops. Objects that
1996 * refer to themselves will cause infinite recursion.
1997 *
1998 * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies
1999 * UIDs created by <code>getUid</code> into cloned results.
2000 *
2001 * @param {*} obj The value to clone.
2002 * @return {*} A clone of the input value.
2003 * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods.
2004 */
2005goog.cloneObject = function(obj) {
2006 var type = goog.typeOf(obj);
2007 if (type == 'object' || type == 'array') {
2008 if (obj.clone) {
2009 return obj.clone();
2010 }
2011 var clone = type == 'array' ? [] : {};
2012 for (var key in obj) {
2013 clone[key] = goog.cloneObject(obj[key]);
2014 }
2015 return clone;
2016 }
2017
2018 return obj;
2019};
2020
2021
2022/**
2023 * A native implementation of goog.bind.
2024 * @param {?function(this:T, ...)} fn A function to partially apply.
2025 * @param {T} selfObj Specifies the object which this should point to when the
2026 * function is run.
2027 * @param {...*} var_args Additional arguments that are partially applied to the
2028 * function.
2029 * @return {!Function} A partially-applied form of the function goog.bind() was
2030 * invoked as a method of.
2031 * @template T
2032 * @private
2033 */
2034goog.bindNative_ = function(fn, selfObj, var_args) {
2035 return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));
2036};
2037
2038
2039/**
2040 * A pure-JS implementation of goog.bind.
2041 * @param {?function(this:T, ...)} fn A function to partially apply.
2042 * @param {T} selfObj Specifies the object which this should point to when the
2043 * function is run.
2044 * @param {...*} var_args Additional arguments that are partially applied to the
2045 * function.
2046 * @return {!Function} A partially-applied form of the function goog.bind() was
2047 * invoked as a method of.
2048 * @template T
2049 * @private
2050 */
2051goog.bindJs_ = function(fn, selfObj, var_args) {
2052 if (!fn) {
2053 throw new Error();
2054 }
2055
2056 if (arguments.length > 2) {
2057 var boundArgs = Array.prototype.slice.call(arguments, 2);
2058 return function() {
2059 // Prepend the bound arguments to the current arguments.
2060 var newArgs = Array.prototype.slice.call(arguments);
2061 Array.prototype.unshift.apply(newArgs, boundArgs);
2062 return fn.apply(selfObj, newArgs);
2063 };
2064
2065 } else {
2066 return function() {
2067 return fn.apply(selfObj, arguments);
2068 };
2069 }
2070};
2071
2072
2073/**
2074 * Partially applies this function to a particular 'this object' and zero or
2075 * more arguments. The result is a new function with some arguments of the first
2076 * function pre-filled and the value of this 'pre-specified'.
2077 *
2078 * Remaining arguments specified at call-time are appended to the pre-specified
2079 * ones.
2080 *
2081 * Also see: {@link #partial}.
2082 *
2083 * Usage:
2084 * <pre>var barMethBound = goog.bind(myFunction, myObj, 'arg1', 'arg2');
2085 * barMethBound('arg3', 'arg4');</pre>
2086 *
2087 * @param {?function(this:T, ...)} fn A function to partially apply.
2088 * @param {T} selfObj Specifies the object which this should point to when the
2089 * function is run.
2090 * @param {...*} var_args Additional arguments that are partially applied to the
2091 * function.
2092 * @return {!Function} A partially-applied form of the function goog.bind() was
2093 * invoked as a method of.
2094 * @template T
2095 * @suppress {deprecated} See above.
2096 */
2097goog.bind = function(fn, selfObj, var_args) {
2098 // TODO(nicksantos): narrow the type signature.
2099 if (Function.prototype.bind &&
2100 // NOTE(nicksantos): Somebody pulled base.js into the default Chrome
2101 // extension environment. This means that for Chrome extensions, they get
2102 // the implementation of Function.prototype.bind that calls goog.bind
2103 // instead of the native one. Even worse, we don't want to introduce a
2104 // circular dependency between goog.bind and Function.prototype.bind, so
2105 // we have to hack this to make sure it works correctly.
2106 Function.prototype.bind.toString().indexOf('native code') != -1) {
2107 goog.bind = goog.bindNative_;
2108 } else {
2109 goog.bind = goog.bindJs_;
2110 }
2111 return goog.bind.apply(null, arguments);
2112};
2113
2114
2115/**
2116 * Like goog.bind(), except that a 'this object' is not required. Useful when
2117 * the target function is already bound.
2118 *
2119 * Usage:
2120 * var g = goog.partial(f, arg1, arg2);
2121 * g(arg3, arg4);
2122 *
2123 * @param {Function} fn A function to partially apply.
2124 * @param {...*} var_args Additional arguments that are partially applied to fn.
2125 * @return {!Function} A partially-applied form of the function goog.partial()
2126 * was invoked as a method of.
2127 */
2128goog.partial = function(fn, var_args) {
2129 var args = Array.prototype.slice.call(arguments, 1);
2130 return function() {
2131 // Clone the array (with slice()) and append additional arguments
2132 // to the existing arguments.
2133 var newArgs = args.slice();
2134 newArgs.push.apply(newArgs, arguments);
2135 return fn.apply(this, newArgs);
2136 };
2137};
2138
2139
2140/**
2141 * Copies all the members of a source object to a target object. This method
2142 * does not work on all browsers for all objects that contain keys such as
2143 * toString or hasOwnProperty. Use goog.object.extend for this purpose.
2144 * @param {Object} target Target.
2145 * @param {Object} source Source.
2146 */
2147goog.mixin = function(target, source) {
2148 for (var x in source) {
2149 target[x] = source[x];
2150 }
2151
2152 // For IE7 or lower, the for-in-loop does not contain any properties that are
2153 // not enumerable on the prototype object (for example, isPrototypeOf from
2154 // Object.prototype) but also it will not include 'replace' on objects that
2155 // extend String and change 'replace' (not that it is common for anyone to
2156 // extend anything except Object).
2157};
2158
2159
2160/**
2161 * @return {number} An integer value representing the number of milliseconds
2162 * between midnight, January 1, 1970 and the current time.
2163 */
2164goog.now = (goog.TRUSTED_SITE && Date.now) || (function() {
2165 // Unary plus operator converts its operand to a number which in
2166 // the case of
2167 // a date is done by calling getTime().
2168 return +new Date();
2169 });
2170
2171
2172/**
2173 * Evals JavaScript in the global scope. In IE this uses execScript, other
2174 * browsers use goog.global.eval. If goog.global.eval does not evaluate in the
2175 * global scope (for example, in Safari), appends a script tag instead.
2176 * Throws an exception if neither execScript or eval is defined.
2177 * @param {string} script JavaScript string.
2178 */
2179goog.globalEval = function(script) {
2180 if (goog.global.execScript) {
2181 goog.global.execScript(script, 'JavaScript');
2182 } else if (goog.global.eval) {
2183 // Test to see if eval works
2184 if (goog.evalWorksForGlobals_ == null) {
2185 goog.global.eval('var _evalTest_ = 1;');
2186 if (typeof goog.global['_evalTest_'] != 'undefined') {
2187 try {
2188 delete goog.global['_evalTest_'];
2189 } catch (ignore) {
2190 // Microsoft edge fails the deletion above in strict mode.
2191 }
2192 goog.evalWorksForGlobals_ = true;
2193 } else {
2194 goog.evalWorksForGlobals_ = false;
2195 }
2196 }
2197
2198 if (goog.evalWorksForGlobals_) {
2199 goog.global.eval(script);
2200 } else {
2201 /** @type {Document} */
2202 var doc = goog.global.document;
2203 var scriptElt =
2204 /** @type {!HTMLScriptElement} */ (doc.createElement('SCRIPT'));
2205 scriptElt.type = 'text/javascript';
2206 scriptElt.defer = false;
2207 // Note(user): can't use .innerHTML since "t('<test>')" will fail and
2208 // .text doesn't work in Safari 2. Therefore we append a text node.
2209 scriptElt.appendChild(doc.createTextNode(script));
2210 doc.body.appendChild(scriptElt);
2211 doc.body.removeChild(scriptElt);
2212 }
2213 } else {
2214 throw Error('goog.globalEval not available');
2215 }
2216};
2217
2218
2219/**
2220 * Indicates whether or not we can call 'eval' directly to eval code in the
2221 * global scope. Set to a Boolean by the first call to goog.globalEval (which
2222 * empirically tests whether eval works for globals). @see goog.globalEval
2223 * @type {?boolean}
2224 * @private
2225 */
2226goog.evalWorksForGlobals_ = null;
2227
2228
2229/**
2230 * Optional map of CSS class names to obfuscated names used with
2231 * goog.getCssName().
2232 * @private {!Object<string, string>|undefined}
2233 * @see goog.setCssNameMapping
2234 */
2235goog.cssNameMapping_;
2236
2237
2238/**
2239 * Optional obfuscation style for CSS class names. Should be set to either
2240 * 'BY_WHOLE' or 'BY_PART' if defined.
2241 * @type {string|undefined}
2242 * @private
2243 * @see goog.setCssNameMapping
2244 */
2245goog.cssNameMappingStyle_;
2246
2247
2248
2249/**
2250 * A hook for modifying the default behavior goog.getCssName. The function
2251 * if present, will recieve the standard output of the goog.getCssName as
2252 * its input.
2253 *
2254 * @type {(function(string):string)|undefined}
2255 */
2256goog.global.CLOSURE_CSS_NAME_MAP_FN;
2257
2258
2259/**
2260 * Handles strings that are intended to be used as CSS class names.
2261 *
2262 * This function works in tandem with @see goog.setCssNameMapping.
2263 *
2264 * Without any mapping set, the arguments are simple joined with a hyphen and
2265 * passed through unaltered.
2266 *
2267 * When there is a mapping, there are two possible styles in which these
2268 * mappings are used. In the BY_PART style, each part (i.e. in between hyphens)
2269 * of the passed in css name is rewritten according to the map. In the BY_WHOLE
2270 * style, the full css name is looked up in the map directly. If a rewrite is
2271 * not specified by the map, the compiler will output a warning.
2272 *
2273 * When the mapping is passed to the compiler, it will replace calls to
2274 * goog.getCssName with the strings from the mapping, e.g.
2275 * var x = goog.getCssName('foo');
2276 * var y = goog.getCssName(this.baseClass, 'active');
2277 * becomes:
2278 * var x = 'foo';
2279 * var y = this.baseClass + '-active';
2280 *
2281 * If one argument is passed it will be processed, if two are passed only the
2282 * modifier will be processed, as it is assumed the first argument was generated
2283 * as a result of calling goog.getCssName.
2284 *
2285 * @param {string} className The class name.
2286 * @param {string=} opt_modifier A modifier to be appended to the class name.
2287 * @return {string} The class name or the concatenation of the class name and
2288 * the modifier.
2289 */
2290goog.getCssName = function(className, opt_modifier) {
2291 // String() is used for compatibility with compiled soy where the passed
2292 // className can be non-string objects.
2293 if (String(className).charAt(0) == '.') {
2294 throw new Error(
2295 'className passed in goog.getCssName must not start with ".".' +
2296 ' You passed: ' + className);
2297 }
2298
2299 var getMapping = function(cssName) {
2300 return goog.cssNameMapping_[cssName] || cssName;
2301 };
2302
2303 var renameByParts = function(cssName) {
2304 // Remap all the parts individually.
2305 var parts = cssName.split('-');
2306 var mapped = [];
2307 for (var i = 0; i < parts.length; i++) {
2308 mapped.push(getMapping(parts[i]));
2309 }
2310 return mapped.join('-');
2311 };
2312
2313 var rename;
2314 if (goog.cssNameMapping_) {
2315 rename =
2316 goog.cssNameMappingStyle_ == 'BY_WHOLE' ? getMapping : renameByParts;
2317 } else {
2318 rename = function(a) {
2319 return a;
2320 };
2321 }
2322
2323 var result =
2324 opt_modifier ? className + '-' + rename(opt_modifier) : rename(className);
2325
2326 // The special CLOSURE_CSS_NAME_MAP_FN allows users to specify further
2327 // processing of the class name.
2328 if (goog.global.CLOSURE_CSS_NAME_MAP_FN) {
2329 return goog.global.CLOSURE_CSS_NAME_MAP_FN(result);
2330 }
2331
2332 return result;
2333};
2334
2335
2336/**
2337 * Sets the map to check when returning a value from goog.getCssName(). Example:
2338 * <pre>
2339 * goog.setCssNameMapping({
2340 * "goog": "a",
2341 * "disabled": "b",
2342 * });
2343 *
2344 * var x = goog.getCssName('goog');
2345 * // The following evaluates to: "a a-b".
2346 * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled')
2347 * </pre>
2348 * When declared as a map of string literals to string literals, the JSCompiler
2349 * will replace all calls to goog.getCssName() using the supplied map if the
2350 * --process_closure_primitives flag is set.
2351 *
2352 * @param {!Object} mapping A map of strings to strings where keys are possible
2353 * arguments to goog.getCssName() and values are the corresponding values
2354 * that should be returned.
2355 * @param {string=} opt_style The style of css name mapping. There are two valid
2356 * options: 'BY_PART', and 'BY_WHOLE'.
2357 * @see goog.getCssName for a description.
2358 */
2359goog.setCssNameMapping = function(mapping, opt_style) {
2360 goog.cssNameMapping_ = mapping;
2361 goog.cssNameMappingStyle_ = opt_style;
2362};
2363
2364
2365/**
2366 * To use CSS renaming in compiled mode, one of the input files should have a
2367 * call to goog.setCssNameMapping() with an object literal that the JSCompiler
2368 * can extract and use to replace all calls to goog.getCssName(). In uncompiled
2369 * mode, JavaScript code should be loaded before this base.js file that declares
2370 * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is
2371 * to ensure that the mapping is loaded before any calls to goog.getCssName()
2372 * are made in uncompiled mode.
2373 *
2374 * A hook for overriding the CSS name mapping.
2375 * @type {!Object<string, string>|undefined}
2376 */
2377goog.global.CLOSURE_CSS_NAME_MAPPING;
2378
2379
2380if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) {
2381 // This does not call goog.setCssNameMapping() because the JSCompiler
2382 // requires that goog.setCssNameMapping() be called with an object literal.
2383 goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING;
2384}
2385
2386
2387/**
2388 * Gets a localized message.
2389 *
2390 * This function is a compiler primitive. If you give the compiler a localized
2391 * message bundle, it will replace the string at compile-time with a localized
2392 * version, and expand goog.getMsg call to a concatenated string.
2393 *
2394 * Messages must be initialized in the form:
2395 * <code>
2396 * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'});
2397 * </code>
2398 *
2399 * This function produces a string which should be treated as plain text. Use
2400 * {@link goog.html.SafeHtmlFormatter} in conjunction with goog.getMsg to
2401 * produce SafeHtml.
2402 *
2403 * @param {string} str Translatable string, places holders in the form {$foo}.
2404 * @param {Object<string, string>=} opt_values Maps place holder name to value.
2405 * @return {string} message with placeholders filled.
2406 */
2407goog.getMsg = function(str, opt_values) {
2408 if (opt_values) {
2409 str = str.replace(/\{\$([^}]+)}/g, function(match, key) {
2410 return (opt_values != null && key in opt_values) ? opt_values[key] :
2411 match;
2412 });
2413 }
2414 return str;
2415};
2416
2417
2418/**
2419 * Gets a localized message. If the message does not have a translation, gives a
2420 * fallback message.
2421 *
2422 * This is useful when introducing a new message that has not yet been
2423 * translated into all languages.
2424 *
2425 * This function is a compiler primitive. Must be used in the form:
2426 * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code>
2427 * where MSG_A and MSG_B were initialized with goog.getMsg.
2428 *
2429 * @param {string} a The preferred message.
2430 * @param {string} b The fallback message.
2431 * @return {string} The best translated message.
2432 */
2433goog.getMsgWithFallback = function(a, b) {
2434 return a;
2435};
2436
2437
2438/**
2439 * Exposes an unobfuscated global namespace path for the given object.
2440 * Note that fields of the exported object *will* be obfuscated, unless they are
2441 * exported in turn via this function or goog.exportProperty.
2442 *
2443 * Also handy for making public items that are defined in anonymous closures.
2444 *
2445 * ex. goog.exportSymbol('public.path.Foo', Foo);
2446 *
2447 * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction);
2448 * public.path.Foo.staticFunction();
2449 *
2450 * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod',
2451 * Foo.prototype.myMethod);
2452 * new public.path.Foo().myMethod();
2453 *
2454 * @param {string} publicPath Unobfuscated name to export.
2455 * @param {*} object Object the name should point to.
2456 * @param {Object=} opt_objectToExportTo The object to add the path to; default
2457 * is goog.global.
2458 */
2459goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) {
2460 goog.exportPath_(publicPath, object, opt_objectToExportTo);
2461};
2462
2463
2464/**
2465 * Exports a property unobfuscated into the object's namespace.
2466 * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction);
2467 * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod);
2468 * @param {Object} object Object whose static property is being exported.
2469 * @param {string} publicName Unobfuscated name to export.
2470 * @param {*} symbol Object the name should point to.
2471 */
2472goog.exportProperty = function(object, publicName, symbol) {
2473 object[publicName] = symbol;
2474};
2475
2476
2477/**
2478 * Inherit the prototype methods from one constructor into another.
2479 *
2480 * Usage:
2481 * <pre>
2482 * function ParentClass(a, b) { }
2483 * ParentClass.prototype.foo = function(a) { };
2484 *
2485 * function ChildClass(a, b, c) {
2486 * ChildClass.base(this, 'constructor', a, b);
2487 * }
2488 * goog.inherits(ChildClass, ParentClass);
2489 *
2490 * var child = new ChildClass('a', 'b', 'see');
2491 * child.foo(); // This works.
2492 * </pre>
2493 *
2494 * @param {!Function} childCtor Child class.
2495 * @param {!Function} parentCtor Parent class.
2496 */
2497goog.inherits = function(childCtor, parentCtor) {
2498 /** @constructor */
2499 function tempCtor() {}
2500 tempCtor.prototype = parentCtor.prototype;
2501 childCtor.superClass_ = parentCtor.prototype;
2502 childCtor.prototype = new tempCtor();
2503 /** @override */
2504 childCtor.prototype.constructor = childCtor;
2505
2506 /**
2507 * Calls superclass constructor/method.
2508 *
2509 * This function is only available if you use goog.inherits to
2510 * express inheritance relationships between classes.
2511 *
2512 * NOTE: This is a replacement for goog.base and for superClass_
2513 * property defined in childCtor.
2514 *
2515 * @param {!Object} me Should always be "this".
2516 * @param {string} methodName The method name to call. Calling
2517 * superclass constructor can be done with the special string
2518 * 'constructor'.
2519 * @param {...*} var_args The arguments to pass to superclass
2520 * method/constructor.
2521 * @return {*} The return value of the superclass method/constructor.
2522 */
2523 childCtor.base = function(me, methodName, var_args) {
2524 // Copying using loop to avoid deop due to passing arguments object to
2525 // function. This is faster in many JS engines as of late 2014.
2526 var args = new Array(arguments.length - 2);
2527 for (var i = 2; i < arguments.length; i++) {
2528 args[i - 2] = arguments[i];
2529 }
2530 return parentCtor.prototype[methodName].apply(me, args);
2531 };
2532};
2533
2534
2535/**
2536 * Call up to the superclass.
2537 *
2538 * If this is called from a constructor, then this calls the superclass
2539 * constructor with arguments 1-N.
2540 *
2541 * If this is called from a prototype method, then you must pass the name of the
2542 * method as the second argument to this function. If you do not, you will get a
2543 * runtime error. This calls the superclass' method with arguments 2-N.
2544 *
2545 * This function only works if you use goog.inherits to express inheritance
2546 * relationships between your classes.
2547 *
2548 * This function is a compiler primitive. At compile-time, the compiler will do
2549 * macro expansion to remove a lot of the extra overhead that this function
2550 * introduces. The compiler will also enforce a lot of the assumptions that this
2551 * function makes, and treat it as a compiler error if you break them.
2552 *
2553 * @param {!Object} me Should always be "this".
2554 * @param {*=} opt_methodName The method name if calling a super method.
2555 * @param {...*} var_args The rest of the arguments.
2556 * @return {*} The return value of the superclass method.
2557 * @suppress {es5Strict} This method can not be used in strict mode, but
2558 * all Closure Library consumers must depend on this file.
2559 * @deprecated goog.base is not strict mode compatible. Prefer the static
2560 * "base" method added to the constructor by goog.inherits
2561 * or ES6 classes and the "super" keyword.
2562 */
2563goog.base = function(me, opt_methodName, var_args) {
2564 var caller = arguments.callee.caller;
2565
2566 if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) {
2567 throw Error(
2568 'arguments.caller not defined. goog.base() cannot be used ' +
2569 'with strict mode code. See ' +
2570 'http://www.ecma-international.org/ecma-262/5.1/#sec-C');
2571 }
2572
2573 if (caller.superClass_) {
2574 // Copying using loop to avoid deop due to passing arguments object to
2575 // function. This is faster in many JS engines as of late 2014.
2576 var ctorArgs = new Array(arguments.length - 1);
2577 for (var i = 1; i < arguments.length; i++) {
2578 ctorArgs[i - 1] = arguments[i];
2579 }
2580 // This is a constructor. Call the superclass constructor.
2581 return caller.superClass_.constructor.apply(me, ctorArgs);
2582 }
2583
2584 // Copying using loop to avoid deop due to passing arguments object to
2585 // function. This is faster in many JS engines as of late 2014.
2586 var args = new Array(arguments.length - 2);
2587 for (var i = 2; i < arguments.length; i++) {
2588 args[i - 2] = arguments[i];
2589 }
2590 var foundCaller = false;
2591 for (var ctor = me.constructor; ctor;
2592 ctor = ctor.superClass_ && ctor.superClass_.constructor) {
2593 if (ctor.prototype[opt_methodName] === caller) {
2594 foundCaller = true;
2595 } else if (foundCaller) {
2596 return ctor.prototype[opt_methodName].apply(me, args);
2597 }
2598 }
2599
2600 // If we did not find the caller in the prototype chain, then one of two
2601 // things happened:
2602 // 1) The caller is an instance method.
2603 // 2) This method was not called by the right caller.
2604 if (me[opt_methodName] === caller) {
2605 return me.constructor.prototype[opt_methodName].apply(me, args);
2606 } else {
2607 throw Error(
2608 'goog.base called from a method of one name ' +
2609 'to a method of a different name');
2610 }
2611};
2612
2613
2614/**
2615 * Allow for aliasing within scope functions. This function exists for
2616 * uncompiled code - in compiled code the calls will be inlined and the aliases
2617 * applied. In uncompiled code the function is simply run since the aliases as
2618 * written are valid JavaScript.
2619 *
2620 *
2621 * @param {function()} fn Function to call. This function can contain aliases
2622 * to namespaces (e.g. "var dom = goog.dom") or classes
2623 * (e.g. "var Timer = goog.Timer").
2624 */
2625goog.scope = function(fn) {
2626 if (goog.isInModuleLoader_()) {
2627 throw Error('goog.scope is not supported within a goog.module.');
2628 }
2629 fn.call(goog.global);
2630};
2631
2632
2633/*
2634 * To support uncompiled, strict mode bundles that use eval to divide source
2635 * like so:
2636 * eval('someSource;//# sourceUrl sourcefile.js');
2637 * We need to export the globally defined symbols "goog" and "COMPILED".
2638 * Exporting "goog" breaks the compiler optimizations, so we required that
2639 * be defined externally.
2640 * NOTE: We don't use goog.exportSymbol here because we don't want to trigger
2641 * extern generation when that compiler option is enabled.
2642 */
2643if (!COMPILED) {
2644 goog.global['COMPILED'] = COMPILED;
2645}
2646
2647
2648//==============================================================================
2649// goog.defineClass implementation
2650//==============================================================================
2651
2652
2653/**
2654 * Creates a restricted form of a Closure "class":
2655 * - from the compiler's perspective, the instance returned from the
2656 * constructor is sealed (no new properties may be added). This enables
2657 * better checks.
2658 * - the compiler will rewrite this definition to a form that is optimal
2659 * for type checking and optimization (initially this will be a more
2660 * traditional form).
2661 *
2662 * @param {Function} superClass The superclass, Object or null.
2663 * @param {goog.defineClass.ClassDescriptor} def
2664 * An object literal describing
2665 * the class. It may have the following properties:
2666 * "constructor": the constructor function
2667 * "statics": an object literal containing methods to add to the constructor
2668 * as "static" methods or a function that will receive the constructor
2669 * function as its only parameter to which static properties can
2670 * be added.
2671 * all other properties are added to the prototype.
2672 * @return {!Function} The class constructor.
2673 */
2674goog.defineClass = function(superClass, def) {
2675 // TODO(johnlenz): consider making the superClass an optional parameter.
2676 var constructor = def.constructor;
2677 var statics = def.statics;
2678 // Wrap the constructor prior to setting up the prototype and static methods.
2679 if (!constructor || constructor == Object.prototype.constructor) {
2680 constructor = function() {
2681 throw Error('cannot instantiate an interface (no constructor defined).');
2682 };
2683 }
2684
2685 var cls = goog.defineClass.createSealingConstructor_(constructor, superClass);
2686 if (superClass) {
2687 goog.inherits(cls, superClass);
2688 }
2689
2690 // Remove all the properties that should not be copied to the prototype.
2691 delete def.constructor;
2692 delete def.statics;
2693
2694 goog.defineClass.applyProperties_(cls.prototype, def);
2695 if (statics != null) {
2696 if (statics instanceof Function) {
2697 statics(cls);
2698 } else {
2699 goog.defineClass.applyProperties_(cls, statics);
2700 }
2701 }
2702
2703 return cls;
2704};
2705
2706
2707/**
2708 * @typedef {{
2709 * constructor: (!Function|undefined),
2710 * statics: (Object|undefined|function(Function):void)
2711 * }}
2712 */
2713goog.defineClass.ClassDescriptor;
2714
2715
2716/**
2717 * @define {boolean} Whether the instances returned by goog.defineClass should
2718 * be sealed when possible.
2719 *
2720 * When sealing is disabled the constructor function will not be wrapped by
2721 * goog.defineClass, making it incompatible with ES6 class methods.
2722 */
2723goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG);
2724
2725
2726/**
2727 * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is
2728 * defined, this function will wrap the constructor in a function that seals the
2729 * results of the provided constructor function.
2730 *
2731 * @param {!Function} ctr The constructor whose results maybe be sealed.
2732 * @param {Function} superClass The superclass constructor.
2733 * @return {!Function} The replacement constructor.
2734 * @private
2735 */
2736goog.defineClass.createSealingConstructor_ = function(ctr, superClass) {
2737 if (!goog.defineClass.SEAL_CLASS_INSTANCES) {
2738 // Do now wrap the constructor when sealing is disabled. Angular code
2739 // depends on this for injection to work properly.
2740 return ctr;
2741 }
2742
2743 // Compute whether the constructor is sealable at definition time, rather
2744 // than when the instance is being constructed.
2745 var superclassSealable = !goog.defineClass.isUnsealable_(superClass);
2746
2747 /**
2748 * @this {Object}
2749 * @return {?}
2750 */
2751 var wrappedCtr = function() {
2752 // Don't seal an instance of a subclass when it calls the constructor of
2753 // its super class as there is most likely still setup to do.
2754 var instance = ctr.apply(this, arguments) || this;
2755 instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_];
2756
2757 if (this.constructor === wrappedCtr && superclassSealable &&
2758 Object.seal instanceof Function) {
2759 Object.seal(instance);
2760 }
2761 return instance;
2762 };
2763
2764 return wrappedCtr;
2765};
2766
2767
2768/**
2769 * @param {Function} ctr The constructor to test.
2770 * @return {boolean} Whether the constructor has been tagged as unsealable
2771 * using goog.tagUnsealableClass.
2772 * @private
2773 */
2774goog.defineClass.isUnsealable_ = function(ctr) {
2775 return ctr && ctr.prototype &&
2776 ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_];
2777};
2778
2779
2780// TODO(johnlenz): share these values with the goog.object
2781/**
2782 * The names of the fields that are defined on Object.prototype.
2783 * @type {!Array<string>}
2784 * @private
2785 * @const
2786 */
2787goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [
2788 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
2789 'toLocaleString', 'toString', 'valueOf'
2790];
2791
2792
2793// TODO(johnlenz): share this function with the goog.object
2794/**
2795 * @param {!Object} target The object to add properties to.
2796 * @param {!Object} source The object to copy properties from.
2797 * @private
2798 */
2799goog.defineClass.applyProperties_ = function(target, source) {
2800 // TODO(johnlenz): update this to support ES5 getters/setters
2801
2802 var key;
2803 for (key in source) {
2804 if (Object.prototype.hasOwnProperty.call(source, key)) {
2805 target[key] = source[key];
2806 }
2807 }
2808
2809 // For IE the for-in-loop does not contain any properties that are not
2810 // enumerable on the prototype object (for example isPrototypeOf from
2811 // Object.prototype) and it will also not include 'replace' on objects that
2812 // extend String and change 'replace' (not that it is common for anyone to
2813 // extend anything except Object).
2814 for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) {
2815 key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i];
2816 if (Object.prototype.hasOwnProperty.call(source, key)) {
2817 target[key] = source[key];
2818 }
2819 }
2820};
2821
2822
2823/**
2824 * Sealing classes breaks the older idiom of assigning properties on the
2825 * prototype rather than in the constructor. As such, goog.defineClass
2826 * must not seal subclasses of these old-style classes until they are fixed.
2827 * Until then, this marks a class as "broken", instructing defineClass
2828 * not to seal subclasses.
2829 * @param {!Function} ctr The legacy constructor to tag as unsealable.
2830 */
2831goog.tagUnsealableClass = function(ctr) {
2832 if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) {
2833 ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true;
2834 }
2835};
2836
2837
2838/**
2839 * Name for unsealable tag property.
2840 * @const @private {string}
2841 */
2842goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable';
2843
2844
2845/**
2846 * Returns a newly created map from language mode string to a boolean
2847 * indicating whether transpilation should be done for that mode.
2848 *
2849 * Guaranteed invariant:
2850 * For any two modes, l1 and l2 where l2 is a newer mode than l1,
2851 * `map[l1] == true` implies that `map[l2] == true`.
2852 * @private
2853 * @return {!Object<string, boolean>}
2854 */
2855goog.createRequiresTranspilation_ = function() {
2856 var /** !Object<string, boolean> */ requiresTranspilation = {'es3': false};
2857 var transpilationRequiredForAllLaterModes = false;
2858
2859 /**
2860 * Adds an entry to requiresTranspliation for the given language mode.
2861 *
2862 * IMPORTANT: Calls must be made in order from oldest to newest language
2863 * mode.
2864 * @param {string} modeName
2865 * @param {function(): boolean} isSupported Returns true if the JS engine
2866 * supports the given mode.
2867 */
2868 function addNewerLanguageTranspilationCheck(modeName, isSupported) {
2869 if (transpilationRequiredForAllLaterModes) {
2870 requiresTranspilation[modeName] = true;
2871 } else if (isSupported()) {
2872 requiresTranspilation[modeName] = false;
2873 } else {
2874 requiresTranspilation[modeName] = true;
2875 transpilationRequiredForAllLaterModes = true;
2876 }
2877 }
2878
2879 /**
2880 * Does the given code evaluate without syntax errors and return a truthy
2881 * result?
2882 */
2883 function /** boolean */ evalCheck(/** string */ code) {
2884 try {
2885 return !!eval(code);
2886 } catch (ignored) {
2887 return false;
2888 }
2889 }
2890
2891 var userAgent = goog.global.navigator && goog.global.navigator.userAgent ?
2892 goog.global.navigator.userAgent :
2893 '';
2894
2895 // Identify ES3-only browsers by their incorrect treatment of commas.
2896 addNewerLanguageTranspilationCheck('es5', function() {
2897 return evalCheck('[1,].length==1');
2898 });
2899 addNewerLanguageTranspilationCheck('es6', function() {
2900 // Edge has a non-deterministic (i.e., not reproducible) bug with ES6:
2901 // https://github.com/Microsoft/ChakraCore/issues/1496.
2902 var re = /Edge\/(\d+)(\.\d)*/i;
2903 var edgeUserAgent = userAgent.match(re);
2904 if (edgeUserAgent && Number(edgeUserAgent[1]) < 15) {
2905 return false;
2906 }
2907 // Test es6: [FF50 (?), Edge 14 (?), Chrome 50]
2908 // (a) default params (specifically shadowing locals),
2909 // (b) destructuring, (c) block-scoped functions,
2910 // (d) for-of (const), (e) new.target/Reflect.construct
2911 var es6fullTest =
2912 'class X{constructor(){if(new.target!=String)throw 1;this.x=42}}' +
2913 'let q=Reflect.construct(X,[],String);if(q.x!=42||!(q instanceof ' +
2914 'String))throw 1;for(const a of[2,3]){if(a==2)continue;function ' +
2915 'f(z={a}){let a=0;return z.a}{function f(){return 0;}}return f()' +
2916 '==3}';
2917
2918 return evalCheck('(()=>{"use strict";' + es6fullTest + '})()');
2919 });
2920 // TODO(joeltine): Remove es6-impl references for b/31340605.
2921 // Consider es6-impl (widely-implemented es6 features) to be supported
2922 // whenever es6 is supported. Technically es6-impl is a lower level of
2923 // support than es6, but we don't have tests specifically for it.
2924 addNewerLanguageTranspilationCheck('es6-impl', function() {
2925 return true;
2926 });
2927 // ** and **= are the only new features in 'es7'
2928 addNewerLanguageTranspilationCheck('es7', function() {
2929 return evalCheck('2 ** 2 == 4');
2930 });
2931 // async functions are the only new features in 'es8'
2932 addNewerLanguageTranspilationCheck('es8', function() {
2933 return evalCheck('async () => 1, true');
2934 });
2935 return requiresTranspilation;
2936};
2937
2938goog.provide('ol.array');
2939
2940
2941/**
2942 * Performs a binary search on the provided sorted list and returns the index of the item if found. If it can't be found it'll return -1.
2943 * https://github.com/darkskyapp/binary-search
2944 *
2945 * @param {Array.<*>} haystack Items to search through.
2946 * @param {*} needle The item to look for.
2947 * @param {Function=} opt_comparator Comparator function.
2948 * @return {number} The index of the item if found, -1 if not.
2949 */
2950ol.array.binarySearch = function(haystack, needle, opt_comparator) {
2951 var mid, cmp;
2952 var comparator = opt_comparator || ol.array.numberSafeCompareFunction;
2953 var low = 0;
2954 var high = haystack.length;
2955 var found = false;
2956
2957 while (low < high) {
2958 /* Note that "(low + high) >>> 1" may overflow, and results in a typecast
2959 * to double (which gives the wrong results). */
2960 mid = low + (high - low >> 1);
2961 cmp = +comparator(haystack[mid], needle);
2962
2963 if (cmp < 0.0) { /* Too low. */
2964 low = mid + 1;
2965
2966 } else { /* Key found or too high */
2967 high = mid;
2968 found = !cmp;
2969 }
2970 }
2971
2972 /* Key not found. */
2973 return found ? low : ~low;
2974};
2975
2976
2977/**
2978 * Compare function for array sort that is safe for numbers.
2979 * @param {*} a The first object to be compared.
2980 * @param {*} b The second object to be compared.
2981 * @return {number} A negative number, zero, or a positive number as the first
2982 * argument is less than, equal to, or greater than the second.
2983 */
2984ol.array.numberSafeCompareFunction = function(a, b) {
2985 return a > b ? 1 : a < b ? -1 : 0;
2986};
2987
2988
2989/**
2990 * Whether the array contains the given object.
2991 * @param {Array.<*>} arr The array to test for the presence of the element.
2992 * @param {*} obj The object for which to test.
2993 * @return {boolean} The object is in the array.
2994 */
2995ol.array.includes = function(arr, obj) {
2996 return arr.indexOf(obj) >= 0;
2997};
2998
2999
3000/**
3001 * @param {Array.<number>} arr Array.
3002 * @param {number} target Target.
3003 * @param {number} direction 0 means return the nearest, > 0
3004 * means return the largest nearest, < 0 means return the
3005 * smallest nearest.
3006 * @return {number} Index.
3007 */
3008ol.array.linearFindNearest = function(arr, target, direction) {
3009 var n = arr.length;
3010 if (arr[0] <= target) {
3011 return 0;
3012 } else if (target <= arr[n - 1]) {
3013 return n - 1;
3014 } else {
3015 var i;
3016 if (direction > 0) {
3017 for (i = 1; i < n; ++i) {
3018 if (arr[i] < target) {
3019 return i - 1;
3020 }
3021 }
3022 } else if (direction < 0) {
3023 for (i = 1; i < n; ++i) {
3024 if (arr[i] <= target) {
3025 return i;
3026 }
3027 }
3028 } else {
3029 for (i = 1; i < n; ++i) {
3030 if (arr[i] == target) {
3031 return i;
3032 } else if (arr[i] < target) {
3033 if (arr[i - 1] - target < target - arr[i]) {
3034 return i - 1;
3035 } else {
3036 return i;
3037 }
3038 }
3039 }
3040 }
3041 return n - 1;
3042 }
3043};
3044
3045
3046/**
3047 * @param {Array.<*>} arr Array.
3048 * @param {number} begin Begin index.
3049 * @param {number} end End index.
3050 */
3051ol.array.reverseSubArray = function(arr, begin, end) {
3052 while (begin < end) {
3053 var tmp = arr[begin];
3054 arr[begin] = arr[end];
3055 arr[end] = tmp;
3056 ++begin;
3057 --end;
3058 }
3059};
3060
3061
3062/**
3063 * @param {Array.<VALUE>} arr The array to modify.
3064 * @param {Array.<VALUE>|VALUE} data The elements or arrays of elements
3065 * to add to arr.
3066 * @template VALUE
3067 */
3068ol.array.extend = function(arr, data) {
3069 var i;
3070 var extension = Array.isArray(data) ? data : [data];
3071 var length = extension.length;
3072 for (i = 0; i < length; i++) {
3073 arr[arr.length] = extension[i];
3074 }
3075};
3076
3077
3078/**
3079 * @param {Array.<VALUE>} arr The array to modify.
3080 * @param {VALUE} obj The element to remove.
3081 * @template VALUE
3082 * @return {boolean} If the element was removed.
3083 */
3084ol.array.remove = function(arr, obj) {
3085 var i = arr.indexOf(obj);
3086 var found = i > -1;
3087 if (found) {
3088 arr.splice(i, 1);
3089 }
3090 return found;
3091};
3092
3093
3094/**
3095 * @param {Array.<VALUE>} arr The array to search in.
3096 * @param {function(VALUE, number, ?) : boolean} func The function to compare.
3097 * @template VALUE
3098 * @return {VALUE} The element found.
3099 */
3100ol.array.find = function(arr, func) {
3101 var length = arr.length >>> 0;
3102 var value;
3103
3104 for (var i = 0; i < length; i++) {
3105 value = arr[i];
3106 if (func(value, i, arr)) {
3107 return value;
3108 }
3109 }
3110 return null;
3111};
3112
3113
3114/**
3115 * @param {Array|Uint8ClampedArray} arr1 The first array to compare.
3116 * @param {Array|Uint8ClampedArray} arr2 The second array to compare.
3117 * @return {boolean} Whether the two arrays are equal.
3118 */
3119ol.array.equals = function(arr1, arr2) {
3120 var len1 = arr1.length;
3121 if (len1 !== arr2.length) {
3122 return false;
3123 }
3124 for (var i = 0; i < len1; i++) {
3125 if (arr1[i] !== arr2[i]) {
3126 return false;
3127 }
3128 }
3129 return true;
3130};
3131
3132
3133/**
3134 * @param {Array.<*>} arr The array to sort (modifies original).
3135 * @param {Function} compareFnc Comparison function.
3136 */
3137ol.array.stableSort = function(arr, compareFnc) {
3138 var length = arr.length;
3139 var tmp = Array(arr.length);
3140 var i;
3141 for (i = 0; i < length; i++) {
3142 tmp[i] = {index: i, value: arr[i]};
3143 }
3144 tmp.sort(function(a, b) {
3145 return compareFnc(a.value, b.value) || a.index - b.index;
3146 });
3147 for (i = 0; i < arr.length; i++) {
3148 arr[i] = tmp[i].value;
3149 }
3150};
3151
3152
3153/**
3154 * @param {Array.<*>} arr The array to search in.
3155 * @param {Function} func Comparison function.
3156 * @return {number} Return index.
3157 */
3158ol.array.findIndex = function(arr, func) {
3159 var index;
3160 var found = !arr.every(function(el, idx) {
3161 index = idx;
3162 return !func(el, idx, arr);
3163 });
3164 return found ? index : -1;
3165};
3166
3167
3168/**
3169 * @param {Array.<*>} arr The array to test.
3170 * @param {Function=} opt_func Comparison function.
3171 * @param {boolean=} opt_strict Strictly sorted (default false).
3172 * @return {boolean} Return index.
3173 */
3174ol.array.isSorted = function(arr, opt_func, opt_strict) {
3175 var compare = opt_func || ol.array.numberSafeCompareFunction;
3176 return arr.every(function(currentVal, index) {
3177 if (index === 0) {
3178 return true;
3179 }
3180 var res = compare(arr[index - 1], currentVal);
3181 return !(res > 0 || opt_strict && res === 0);
3182 });
3183};
3184
3185goog.provide('ol');
3186
3187
3188/**
3189 * Constants defined with the define tag cannot be changed in application
3190 * code, but can be set at compile time.
3191 * Some reduce the size of the build in advanced compile mode.
3192 */
3193
3194
3195/**
3196 * @define {boolean} Assume touch. Default is `false`.
3197 */
3198ol.ASSUME_TOUCH = false;
3199
3200
3201/**
3202 * TODO: rename this to something having to do with tile grids
3203 * see https://github.com/openlayers/openlayers/issues/2076
3204 * @define {number} Default maximum zoom for default tile grids.
3205 */
3206ol.DEFAULT_MAX_ZOOM = 42;
3207
3208
3209/**
3210 * @define {number} Default min zoom level for the map view. Default is `0`.
3211 */
3212ol.DEFAULT_MIN_ZOOM = 0;
3213
3214
3215/**
3216 * @define {number} Default maximum allowed threshold (in pixels) for
3217 * reprojection triangulation. Default is `0.5`.
3218 */
3219ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD = 0.5;
3220
3221
3222/**
3223 * @define {number} Default tile size.
3224 */
3225ol.DEFAULT_TILE_SIZE = 256;
3226
3227
3228/**
3229 * @define {string} Default WMS version.
3230 */
3231ol.DEFAULT_WMS_VERSION = '1.3.0';
3232
3233
3234/**
3235 * @define {boolean} Enable the Canvas renderer. Default is `true`. Setting
3236 * this to false at compile time in advanced mode removes all code
3237 * supporting the Canvas renderer from the build.
3238 */
3239ol.ENABLE_CANVAS = true;
3240
3241
3242/**
3243 * @define {boolean} Enable integration with the Proj4js library. Default is
3244 * `true`.
3245 */
3246ol.ENABLE_PROJ4JS = true;
3247
3248
3249/**
3250 * @define {boolean} Enable automatic reprojection of raster sources. Default is
3251 * `true`.
3252 */
3253ol.ENABLE_RASTER_REPROJECTION = true;
3254
3255
3256/**
3257 * @define {boolean} Enable the WebGL renderer. Default is `true`. Setting
3258 * this to false at compile time in advanced mode removes all code
3259 * supporting the WebGL renderer from the build.
3260 */
3261ol.ENABLE_WEBGL = true;
3262
3263
3264/**
3265 * @define {boolean} Include debuggable shader sources. Default is `true`.
3266 * This should be set to `false` for production builds (if `ol.ENABLE_WEBGL`
3267 * is `true`).
3268 */
3269ol.DEBUG_WEBGL = true;
3270
3271
3272/**
3273 * @define {number} The size in pixels of the first atlas image. Default is
3274 * `256`.
3275 */
3276ol.INITIAL_ATLAS_SIZE = 256;
3277
3278
3279/**
3280 * @define {number} The maximum size in pixels of atlas images. Default is
3281 * `-1`, meaning it is not used (and `ol.WEBGL_MAX_TEXTURE_SIZE` is
3282 * used instead).
3283 */
3284ol.MAX_ATLAS_SIZE = -1;
3285
3286
3287/**
3288 * @define {number} Maximum mouse wheel delta.
3289 */
3290ol.MOUSEWHEELZOOM_MAXDELTA = 1;
3291
3292
3293/**
3294 * @define {number} Maximum width and/or height extent ratio that determines
3295 * when the overview map should be zoomed out.
3296 */
3297ol.OVERVIEWMAP_MAX_RATIO = 0.75;
3298
3299
3300/**
3301 * @define {number} Minimum width and/or height extent ratio that determines
3302 * when the overview map should be zoomed in.
3303 */
3304ol.OVERVIEWMAP_MIN_RATIO = 0.1;
3305
3306
3307/**
3308 * @define {number} Maximum number of source tiles for raster reprojection of
3309 * a single tile.
3310 * If too many source tiles are determined to be loaded to create a single
3311 * reprojected tile the browser can become unresponsive or even crash.
3312 * This can happen if the developer defines projections improperly and/or
3313 * with unlimited extents.
3314 * If too many tiles are required, no tiles are loaded and
3315 * `ol.TileState.ERROR` state is set. Default is `100`.
3316 */
3317ol.RASTER_REPROJECTION_MAX_SOURCE_TILES = 100;
3318
3319
3320/**
3321 * @define {number} Maximum number of subdivision steps during raster
3322 * reprojection triangulation. Prevents high memory usage and large
3323 * number of proj4 calls (for certain transformations and areas).
3324 * At most `2*(2^this)` triangles are created for each triangulated
3325 * extent (tile/image). Default is `10`.
3326 */
3327ol.RASTER_REPROJECTION_MAX_SUBDIVISION = 10;
3328
3329
3330/**
3331 * @define {number} Maximum allowed size of triangle relative to world width.
3332 * When transforming corners of world extent between certain projections,
3333 * the resulting triangulation seems to have zero error and no subdivision
3334 * is performed.
3335 * If the triangle width is more than this (relative to world width; 0-1),
3336 * subdivison is forced (up to `ol.RASTER_REPROJECTION_MAX_SUBDIVISION`).
3337 * Default is `0.25`.
3338 */
3339ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH = 0.25;
3340
3341
3342/**
3343 * @define {number} Tolerance for geometry simplification in device pixels.
3344 */
3345ol.SIMPLIFY_TOLERANCE = 0.5;
3346
3347
3348/**
3349 * @define {number} Texture cache high water mark.
3350 */
3351ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK = 1024;
3352
3353
3354/**
3355 * @define {string} OpenLayers version.
3356 */
3357ol.VERSION = '';
3358
3359
3360/**
3361 * The maximum supported WebGL texture size in pixels. If WebGL is not
3362 * supported, the value is set to `undefined`.
3363 * @const
3364 * @type {number|undefined}
3365 */
3366ol.WEBGL_MAX_TEXTURE_SIZE; // value is set in `ol.has`
3367
3368
3369/**
3370 * List of supported WebGL extensions.
3371 * @const
3372 * @type {Array.<string>}
3373 */
3374ol.WEBGL_EXTENSIONS; // value is set in `ol.has`
3375
3376
3377/**
3378 * Inherit the prototype methods from one constructor into another.
3379 *
3380 * Usage:
3381 *
3382 * function ParentClass(a, b) { }
3383 * ParentClass.prototype.foo = function(a) { }
3384 *
3385 * function ChildClass(a, b, c) {
3386 * // Call parent constructor
3387 * ParentClass.call(this, a, b);
3388 * }
3389 * ol.inherits(ChildClass, ParentClass);
3390 *
3391 * var child = new ChildClass('a', 'b', 'see');
3392 * child.foo(); // This works.
3393 *
3394 * @param {!Function} childCtor Child constructor.
3395 * @param {!Function} parentCtor Parent constructor.
3396 * @function
3397 * @api
3398 */
3399ol.inherits = function(childCtor, parentCtor) {
3400 childCtor.prototype = Object.create(parentCtor.prototype);
3401 childCtor.prototype.constructor = childCtor;
3402};
3403
3404
3405/**
3406 * A reusable function, used e.g. as a default for callbacks.
3407 *
3408 * @return {undefined} Nothing.
3409 */
3410ol.nullFunction = function() {};
3411
3412
3413/**
3414 * Gets a unique ID for an object. This mutates the object so that further calls
3415 * with the same object as a parameter returns the same value. Unique IDs are generated
3416 * as a strictly increasing sequence. Adapted from goog.getUid.
3417 *
3418 * @param {Object} obj The object to get the unique ID for.
3419 * @return {number} The unique ID for the object.
3420 */
3421ol.getUid = function(obj) {
3422 return obj.ol_uid ||
3423 (obj.ol_uid = ++ol.uidCounter_);
3424};
3425
3426
3427/**
3428 * Counter for getUid.
3429 * @type {number}
3430 * @private
3431 */
3432ol.uidCounter_ = 0;
3433
3434goog.provide('ol.AssertionError');
3435
3436goog.require('ol');
3437
3438/**
3439 * Error object thrown when an assertion failed. This is an ECMA-262 Error,
3440 * extended with a `code` property.
3441 * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error}
3442 * @constructor
3443 * @extends {Error}
3444 * @implements {oli.AssertionError}
3445 * @param {number} code Error code.
3446 */
3447ol.AssertionError = function(code) {
3448
3449 var path = ol.VERSION ? ol.VERSION.split('-')[0] : 'latest';
3450
3451 /**
3452 * @type {string}
3453 */
3454 this.message = 'Assertion failed. See https://openlayers.org/en/' + path +
3455 '/doc/errors/#' + code + ' for details.';
3456
3457 /**
3458 * Error code. The meaning of the code can be found on
3459 * {@link https://openlayers.org/en/latest/doc/errors/} (replace `latest` with
3460 * the version found in the OpenLayers script's header comment if a version
3461 * other than the latest is used).
3462 * @type {number}
3463 * @api
3464 */
3465 this.code = code;
3466
3467 this.name = 'AssertionError';
3468
3469};
3470ol.inherits(ol.AssertionError, Error);
3471
3472goog.provide('ol.asserts');
3473
3474goog.require('ol.AssertionError');
3475
3476
3477/**
3478 * @param {*} assertion Assertion we expected to be truthy.
3479 * @param {number} errorCode Error code.
3480 */
3481ol.asserts.assert = function(assertion, errorCode) {
3482 if (!assertion) {
3483 throw new ol.AssertionError(errorCode);
3484 }
3485};
3486
3487goog.provide('ol.TileRange');
3488
3489
3490/**
3491 * A representation of a contiguous block of tiles. A tile range is specified
3492 * by its min/max tile coordinates and is inclusive of coordinates.
3493 *
3494 * @constructor
3495 * @param {number} minX Minimum X.
3496 * @param {number} maxX Maximum X.
3497 * @param {number} minY Minimum Y.
3498 * @param {number} maxY Maximum Y.
3499 * @struct
3500 */
3501ol.TileRange = function(minX, maxX, minY, maxY) {
3502
3503 /**
3504 * @type {number}
3505 */
3506 this.minX = minX;
3507
3508 /**
3509 * @type {number}
3510 */
3511 this.maxX = maxX;
3512
3513 /**
3514 * @type {number}
3515 */
3516 this.minY = minY;
3517
3518 /**
3519 * @type {number}
3520 */
3521 this.maxY = maxY;
3522
3523};
3524
3525
3526/**
3527 * @param {number} minX Minimum X.
3528 * @param {number} maxX Maximum X.
3529 * @param {number} minY Minimum Y.
3530 * @param {number} maxY Maximum Y.
3531 * @param {ol.TileRange|undefined} tileRange TileRange.
3532 * @return {ol.TileRange} Tile range.
3533 */
3534ol.TileRange.createOrUpdate = function(minX, maxX, minY, maxY, tileRange) {
3535 if (tileRange !== undefined) {
3536 tileRange.minX = minX;
3537 tileRange.maxX = maxX;
3538 tileRange.minY = minY;
3539 tileRange.maxY = maxY;
3540 return tileRange;
3541 } else {
3542 return new ol.TileRange(minX, maxX, minY, maxY);
3543 }
3544};
3545
3546
3547/**
3548 * @param {ol.TileCoord} tileCoord Tile coordinate.
3549 * @return {boolean} Contains tile coordinate.
3550 */
3551ol.TileRange.prototype.contains = function(tileCoord) {
3552 return this.containsXY(tileCoord[1], tileCoord[2]);
3553};
3554
3555
3556/**
3557 * @param {ol.TileRange} tileRange Tile range.
3558 * @return {boolean} Contains.
3559 */
3560ol.TileRange.prototype.containsTileRange = function(tileRange) {
3561 return this.minX <= tileRange.minX && tileRange.maxX <= this.maxX &&
3562 this.minY <= tileRange.minY && tileRange.maxY <= this.maxY;
3563};
3564
3565
3566/**
3567 * @param {number} x Tile coordinate x.
3568 * @param {number} y Tile coordinate y.
3569 * @return {boolean} Contains coordinate.
3570 */
3571ol.TileRange.prototype.containsXY = function(x, y) {
3572 return this.minX <= x && x <= this.maxX && this.minY <= y && y <= this.maxY;
3573};
3574
3575
3576/**
3577 * @param {ol.TileRange} tileRange Tile range.
3578 * @return {boolean} Equals.
3579 */
3580ol.TileRange.prototype.equals = function(tileRange) {
3581 return this.minX == tileRange.minX && this.minY == tileRange.minY &&
3582 this.maxX == tileRange.maxX && this.maxY == tileRange.maxY;
3583};
3584
3585
3586/**
3587 * @param {ol.TileRange} tileRange Tile range.
3588 */
3589ol.TileRange.prototype.extend = function(tileRange) {
3590 if (tileRange.minX < this.minX) {
3591 this.minX = tileRange.minX;
3592 }
3593 if (tileRange.maxX > this.maxX) {
3594 this.maxX = tileRange.maxX;
3595 }
3596 if (tileRange.minY < this.minY) {
3597 this.minY = tileRange.minY;
3598 }
3599 if (tileRange.maxY > this.maxY) {
3600 this.maxY = tileRange.maxY;
3601 }
3602};
3603
3604
3605/**
3606 * @return {number} Height.
3607 */
3608ol.TileRange.prototype.getHeight = function() {
3609 return this.maxY - this.minY + 1;
3610};
3611
3612
3613/**
3614 * @return {ol.Size} Size.
3615 */
3616ol.TileRange.prototype.getSize = function() {
3617 return [this.getWidth(), this.getHeight()];
3618};
3619
3620
3621/**
3622 * @return {number} Width.
3623 */
3624ol.TileRange.prototype.getWidth = function() {
3625 return this.maxX - this.minX + 1;
3626};
3627
3628
3629/**
3630 * @param {ol.TileRange} tileRange Tile range.
3631 * @return {boolean} Intersects.
3632 */
3633ol.TileRange.prototype.intersects = function(tileRange) {
3634 return this.minX <= tileRange.maxX &&
3635 this.maxX >= tileRange.minX &&
3636 this.minY <= tileRange.maxY &&
3637 this.maxY >= tileRange.minY;
3638};
3639
3640goog.provide('ol.math');
3641
3642goog.require('ol.asserts');
3643
3644
3645/**
3646 * Takes a number and clamps it to within the provided bounds.
3647 * @param {number} value The input number.
3648 * @param {number} min The minimum value to return.
3649 * @param {number} max The maximum value to return.
3650 * @return {number} The input number if it is within bounds, or the nearest
3651 * number within the bounds.
3652 */
3653ol.math.clamp = function(value, min, max) {
3654 return Math.min(Math.max(value, min), max);
3655};
3656
3657
3658/**
3659 * Return the hyperbolic cosine of a given number. The method will use the
3660 * native `Math.cosh` function if it is available, otherwise the hyperbolic
3661 * cosine will be calculated via the reference implementation of the Mozilla
3662 * developer network.
3663 *
3664 * @param {number} x X.
3665 * @return {number} Hyperbolic cosine of x.
3666 */
3667ol.math.cosh = (function() {
3668 // Wrapped in a iife, to save the overhead of checking for the native
3669 // implementation on every invocation.
3670 var cosh;
3671 if ('cosh' in Math) {
3672 // The environment supports the native Math.cosh function, use it…
3673 cosh = Math.cosh;
3674 } else {
3675 // … else, use the reference implementation of MDN:
3676 cosh = function(x) {
3677 var y = Math.exp(x);
3678 return (y + 1 / y) / 2;
3679 };
3680 }
3681 return cosh;
3682}());
3683
3684
3685/**
3686 * @param {number} x X.
3687 * @return {number} The smallest power of two greater than or equal to x.
3688 */
3689ol.math.roundUpToPowerOfTwo = function(x) {
3690 ol.asserts.assert(0 < x, 29); // `x` must be greater than `0`
3691 return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
3692};
3693
3694
3695/**
3696 * Returns the square of the closest distance between the point (x, y) and the
3697 * line segment (x1, y1) to (x2, y2).
3698 * @param {number} x X.
3699 * @param {number} y Y.
3700 * @param {number} x1 X1.
3701 * @param {number} y1 Y1.
3702 * @param {number} x2 X2.
3703 * @param {number} y2 Y2.
3704 * @return {number} Squared distance.
3705 */
3706ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) {
3707 var dx = x2 - x1;
3708 var dy = y2 - y1;
3709 if (dx !== 0 || dy !== 0) {
3710 var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
3711 if (t > 1) {
3712 x1 = x2;
3713 y1 = y2;
3714 } else if (t > 0) {
3715 x1 += dx * t;
3716 y1 += dy * t;
3717 }
3718 }
3719 return ol.math.squaredDistance(x, y, x1, y1);
3720};
3721
3722
3723/**
3724 * Returns the square of the distance between the points (x1, y1) and (x2, y2).
3725 * @param {number} x1 X1.
3726 * @param {number} y1 Y1.
3727 * @param {number} x2 X2.
3728 * @param {number} y2 Y2.
3729 * @return {number} Squared distance.
3730 */
3731ol.math.squaredDistance = function(x1, y1, x2, y2) {
3732 var dx = x2 - x1;
3733 var dy = y2 - y1;
3734 return dx * dx + dy * dy;
3735};
3736
3737
3738/**
3739 * Solves system of linear equations using Gaussian elimination method.
3740 *
3741 * @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column)
3742 * in row-major order.
3743 * @return {Array.<number>} The resulting vector.
3744 */
3745ol.math.solveLinearSystem = function(mat) {
3746 var n = mat.length;
3747
3748 for (var i = 0; i < n; i++) {
3749 // Find max in the i-th column (ignoring i - 1 first rows)
3750 var maxRow = i;
3751 var maxEl = Math.abs(mat[i][i]);
3752 for (var r = i + 1; r < n; r++) {
3753 var absValue = Math.abs(mat[r][i]);
3754 if (absValue > maxEl) {
3755 maxEl = absValue;
3756 maxRow = r;
3757 }
3758 }
3759
3760 if (maxEl === 0) {
3761 return null; // matrix is singular
3762 }
3763
3764 // Swap max row with i-th (current) row
3765 var tmp = mat[maxRow];
3766 mat[maxRow] = mat[i];
3767 mat[i] = tmp;
3768
3769 // Subtract the i-th row to make all the remaining rows 0 in the i-th column
3770 for (var j = i + 1; j < n; j++) {
3771 var coef = -mat[j][i] / mat[i][i];
3772 for (var k = i; k < n + 1; k++) {
3773 if (i == k) {
3774 mat[j][k] = 0;
3775 } else {
3776 mat[j][k] += coef * mat[i][k];
3777 }
3778 }
3779 }
3780 }
3781
3782 // Solve Ax=b for upper triangular matrix A (mat)
3783 var x = new Array(n);
3784 for (var l = n - 1; l >= 0; l--) {
3785 x[l] = mat[l][n] / mat[l][l];
3786 for (var m = l - 1; m >= 0; m--) {
3787 mat[m][n] -= mat[m][l] * x[l];
3788 }
3789 }
3790 return x;
3791};
3792
3793
3794/**
3795 * Converts radians to to degrees.
3796 *
3797 * @param {number} angleInRadians Angle in radians.
3798 * @return {number} Angle in degrees.
3799 */
3800ol.math.toDegrees = function(angleInRadians) {
3801 return angleInRadians * 180 / Math.PI;
3802};
3803
3804
3805/**
3806 * Converts degrees to radians.
3807 *
3808 * @param {number} angleInDegrees Angle in degrees.
3809 * @return {number} Angle in radians.
3810 */
3811ol.math.toRadians = function(angleInDegrees) {
3812 return angleInDegrees * Math.PI / 180;
3813};
3814
3815/**
3816 * Returns the modulo of a / b, depending on the sign of b.
3817 *
3818 * @param {number} a Dividend.
3819 * @param {number} b Divisor.
3820 * @return {number} Modulo.
3821 */
3822ol.math.modulo = function(a, b) {
3823 var r = a % b;
3824 return r * b < 0 ? r + b : r;
3825};
3826
3827/**
3828 * Calculates the linearly interpolated value of x between a and b.
3829 *
3830 * @param {number} a Number
3831 * @param {number} b Number
3832 * @param {number} x Value to be interpolated.
3833 * @return {number} Interpolated value.
3834 */
3835ol.math.lerp = function(a, b, x) {
3836 return a + x * (b - a);
3837};
3838
3839goog.provide('ol.size');
3840
3841
3842/**
3843 * Returns a buffered size.
3844 * @param {ol.Size} size Size.
3845 * @param {number} buffer Buffer.
3846 * @param {ol.Size=} opt_size Optional reusable size array.
3847 * @return {ol.Size} The buffered size.
3848 */
3849ol.size.buffer = function(size, buffer, opt_size) {
3850 if (opt_size === undefined) {
3851 opt_size = [0, 0];
3852 }
3853 opt_size[0] = size[0] + 2 * buffer;
3854 opt_size[1] = size[1] + 2 * buffer;
3855 return opt_size;
3856};
3857
3858
3859/**
3860 * Determines if a size has a positive area.
3861 * @param {ol.Size} size The size to test.
3862 * @return {boolean} The size has a positive area.
3863 */
3864ol.size.hasArea = function(size) {
3865 return size[0] > 0 && size[1] > 0;
3866};
3867
3868
3869/**
3870 * Returns a size scaled by a ratio. The result will be an array of integers.
3871 * @param {ol.Size} size Size.
3872 * @param {number} ratio Ratio.
3873 * @param {ol.Size=} opt_size Optional reusable size array.
3874 * @return {ol.Size} The scaled size.
3875 */
3876ol.size.scale = function(size, ratio, opt_size) {
3877 if (opt_size === undefined) {
3878 opt_size = [0, 0];
3879 }
3880 opt_size[0] = (size[0] * ratio + 0.5) | 0;
3881 opt_size[1] = (size[1] * ratio + 0.5) | 0;
3882 return opt_size;
3883};
3884
3885
3886/**
3887 * Returns an `ol.Size` array for the passed in number (meaning: square) or
3888 * `ol.Size` array.
3889 * (meaning: non-square),
3890 * @param {number|ol.Size} size Width and height.
3891 * @param {ol.Size=} opt_size Optional reusable size array.
3892 * @return {ol.Size} Size.
3893 * @api
3894 */
3895ol.size.toSize = function(size, opt_size) {
3896 if (Array.isArray(size)) {
3897 return size;
3898 } else {
3899 if (opt_size === undefined) {
3900 opt_size = [size, size];
3901 } else {
3902 opt_size[0] = opt_size[1] = /** @type {number} */ (size);
3903 }
3904 return opt_size;
3905 }
3906};
3907
3908goog.provide('ol.extent.Corner');
3909
3910/**
3911 * Extent corner.
3912 * @enum {string}
3913 */
3914ol.extent.Corner = {
3915 BOTTOM_LEFT: 'bottom-left',
3916 BOTTOM_RIGHT: 'bottom-right',
3917 TOP_LEFT: 'top-left',
3918 TOP_RIGHT: 'top-right'
3919};
3920
3921goog.provide('ol.extent.Relationship');
3922
3923
3924/**
3925 * Relationship to an extent.
3926 * @enum {number}
3927 */
3928ol.extent.Relationship = {
3929 UNKNOWN: 0,
3930 INTERSECTING: 1,
3931 ABOVE: 2,
3932 RIGHT: 4,
3933 BELOW: 8,
3934 LEFT: 16
3935};
3936
3937goog.provide('ol.extent');
3938
3939goog.require('ol.asserts');
3940goog.require('ol.extent.Corner');
3941goog.require('ol.extent.Relationship');
3942
3943
3944/**
3945 * Build an extent that includes all given coordinates.
3946 *
3947 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
3948 * @return {ol.Extent} Bounding extent.
3949 * @api
3950 */
3951ol.extent.boundingExtent = function(coordinates) {
3952 var extent = ol.extent.createEmpty();
3953 for (var i = 0, ii = coordinates.length; i < ii; ++i) {
3954 ol.extent.extendCoordinate(extent, coordinates[i]);
3955 }
3956 return extent;
3957};
3958
3959
3960/**
3961 * @param {Array.<number>} xs Xs.
3962 * @param {Array.<number>} ys Ys.
3963 * @param {ol.Extent=} opt_extent Destination extent.
3964 * @private
3965 * @return {ol.Extent} Extent.
3966 */
3967ol.extent.boundingExtentXYs_ = function(xs, ys, opt_extent) {
3968 var minX = Math.min.apply(null, xs);
3969 var minY = Math.min.apply(null, ys);
3970 var maxX = Math.max.apply(null, xs);
3971 var maxY = Math.max.apply(null, ys);
3972 return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
3973};
3974
3975
3976/**
3977 * Return extent increased by the provided value.
3978 * @param {ol.Extent} extent Extent.
3979 * @param {number} value The amount by which the extent should be buffered.
3980 * @param {ol.Extent=} opt_extent Extent.
3981 * @return {ol.Extent} Extent.
3982 * @api
3983 */
3984ol.extent.buffer = function(extent, value, opt_extent) {
3985 if (opt_extent) {
3986 opt_extent[0] = extent[0] - value;
3987 opt_extent[1] = extent[1] - value;
3988 opt_extent[2] = extent[2] + value;
3989 opt_extent[3] = extent[3] + value;
3990 return opt_extent;
3991 } else {
3992 return [
3993 extent[0] - value,
3994 extent[1] - value,
3995 extent[2] + value,
3996 extent[3] + value
3997 ];
3998 }
3999};
4000
4001
4002/**
4003 * Creates a clone of an extent.
4004 *
4005 * @param {ol.Extent} extent Extent to clone.
4006 * @param {ol.Extent=} opt_extent Extent.
4007 * @return {ol.Extent} The clone.
4008 */
4009ol.extent.clone = function(extent, opt_extent) {
4010 if (opt_extent) {
4011 opt_extent[0] = extent[0];
4012 opt_extent[1] = extent[1];
4013 opt_extent[2] = extent[2];
4014 opt_extent[3] = extent[3];
4015 return opt_extent;
4016 } else {
4017 return extent.slice();
4018 }
4019};
4020
4021
4022/**
4023 * @param {ol.Extent} extent Extent.
4024 * @param {number} x X.
4025 * @param {number} y Y.
4026 * @return {number} Closest squared distance.
4027 */
4028ol.extent.closestSquaredDistanceXY = function(extent, x, y) {
4029 var dx, dy;
4030 if (x < extent[0]) {
4031 dx = extent[0] - x;
4032 } else if (extent[2] < x) {
4033 dx = x - extent[2];
4034 } else {
4035 dx = 0;
4036 }
4037 if (y < extent[1]) {
4038 dy = extent[1] - y;
4039 } else if (extent[3] < y) {
4040 dy = y - extent[3];
4041 } else {
4042 dy = 0;
4043 }
4044 return dx * dx + dy * dy;
4045};
4046
4047
4048/**
4049 * Check if the passed coordinate is contained or on the edge of the extent.
4050 *
4051 * @param {ol.Extent} extent Extent.
4052 * @param {ol.Coordinate} coordinate Coordinate.
4053 * @return {boolean} The coordinate is contained in the extent.
4054 * @api
4055 */
4056ol.extent.containsCoordinate = function(extent, coordinate) {
4057 return ol.extent.containsXY(extent, coordinate[0], coordinate[1]);
4058};
4059
4060
4061/**
4062 * Check if one extent contains another.
4063 *
4064 * An extent is deemed contained if it lies completely within the other extent,
4065 * including if they share one or more edges.
4066 *
4067 * @param {ol.Extent} extent1 Extent 1.
4068 * @param {ol.Extent} extent2 Extent 2.
4069 * @return {boolean} The second extent is contained by or on the edge of the
4070 * first.
4071 * @api
4072 */
4073ol.extent.containsExtent = function(extent1, extent2) {
4074 return extent1[0] <= extent2[0] && extent2[2] <= extent1[2] &&
4075 extent1[1] <= extent2[1] && extent2[3] <= extent1[3];
4076};
4077
4078
4079/**
4080 * Check if the passed coordinate is contained or on the edge of the extent.
4081 *
4082 * @param {ol.Extent} extent Extent.
4083 * @param {number} x X coordinate.
4084 * @param {number} y Y coordinate.
4085 * @return {boolean} The x, y values are contained in the extent.
4086 * @api
4087 */
4088ol.extent.containsXY = function(extent, x, y) {
4089 return extent[0] <= x && x <= extent[2] && extent[1] <= y && y <= extent[3];
4090};
4091
4092
4093/**
4094 * Get the relationship between a coordinate and extent.
4095 * @param {ol.Extent} extent The extent.
4096 * @param {ol.Coordinate} coordinate The coordinate.
4097 * @return {number} The relationship (bitwise compare with
4098 * ol.extent.Relationship).
4099 */
4100ol.extent.coordinateRelationship = function(extent, coordinate) {
4101 var minX = extent[0];
4102 var minY = extent[1];
4103 var maxX = extent[2];
4104 var maxY = extent[3];
4105 var x = coordinate[0];
4106 var y = coordinate[1];
4107 var relationship = ol.extent.Relationship.UNKNOWN;
4108 if (x < minX) {
4109 relationship = relationship | ol.extent.Relationship.LEFT;
4110 } else if (x > maxX) {
4111 relationship = relationship | ol.extent.Relationship.RIGHT;
4112 }
4113 if (y < minY) {
4114 relationship = relationship | ol.extent.Relationship.BELOW;
4115 } else if (y > maxY) {
4116 relationship = relationship | ol.extent.Relationship.ABOVE;
4117 }
4118 if (relationship === ol.extent.Relationship.UNKNOWN) {
4119 relationship = ol.extent.Relationship.INTERSECTING;
4120 }
4121 return relationship;
4122};
4123
4124
4125/**
4126 * Create an empty extent.
4127 * @return {ol.Extent} Empty extent.
4128 * @api
4129 */
4130ol.extent.createEmpty = function() {
4131 return [Infinity, Infinity, -Infinity, -Infinity];
4132};
4133
4134
4135/**
4136 * Create a new extent or update the provided extent.
4137 * @param {number} minX Minimum X.
4138 * @param {number} minY Minimum Y.
4139 * @param {number} maxX Maximum X.
4140 * @param {number} maxY Maximum Y.
4141 * @param {ol.Extent=} opt_extent Destination extent.
4142 * @return {ol.Extent} Extent.
4143 */
4144ol.extent.createOrUpdate = function(minX, minY, maxX, maxY, opt_extent) {
4145 if (opt_extent) {
4146 opt_extent[0] = minX;
4147 opt_extent[1] = minY;
4148 opt_extent[2] = maxX;
4149 opt_extent[3] = maxY;
4150 return opt_extent;
4151 } else {
4152 return [minX, minY, maxX, maxY];
4153 }
4154};
4155
4156
4157/**
4158 * Create a new empty extent or make the provided one empty.
4159 * @param {ol.Extent=} opt_extent Extent.
4160 * @return {ol.Extent} Extent.
4161 */
4162ol.extent.createOrUpdateEmpty = function(opt_extent) {
4163 return ol.extent.createOrUpdate(
4164 Infinity, Infinity, -Infinity, -Infinity, opt_extent);
4165};
4166
4167
4168/**
4169 * @param {ol.Coordinate} coordinate Coordinate.
4170 * @param {ol.Extent=} opt_extent Extent.
4171 * @return {ol.Extent} Extent.
4172 */
4173ol.extent.createOrUpdateFromCoordinate = function(coordinate, opt_extent) {
4174 var x = coordinate[0];
4175 var y = coordinate[1];
4176 return ol.extent.createOrUpdate(x, y, x, y, opt_extent);
4177};
4178
4179
4180/**
4181 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
4182 * @param {ol.Extent=} opt_extent Extent.
4183 * @return {ol.Extent} Extent.
4184 */
4185ol.extent.createOrUpdateFromCoordinates = function(coordinates, opt_extent) {
4186 var extent = ol.extent.createOrUpdateEmpty(opt_extent);
4187 return ol.extent.extendCoordinates(extent, coordinates);
4188};
4189
4190
4191/**
4192 * @param {Array.<number>} flatCoordinates Flat coordinates.
4193 * @param {number} offset Offset.
4194 * @param {number} end End.
4195 * @param {number} stride Stride.
4196 * @param {ol.Extent=} opt_extent Extent.
4197 * @return {ol.Extent} Extent.
4198 */
4199ol.extent.createOrUpdateFromFlatCoordinates = function(flatCoordinates, offset, end, stride, opt_extent) {
4200 var extent = ol.extent.createOrUpdateEmpty(opt_extent);
4201 return ol.extent.extendFlatCoordinates(
4202 extent, flatCoordinates, offset, end, stride);
4203};
4204
4205
4206/**
4207 * @param {Array.<Array.<ol.Coordinate>>} rings Rings.
4208 * @param {ol.Extent=} opt_extent Extent.
4209 * @return {ol.Extent} Extent.
4210 */
4211ol.extent.createOrUpdateFromRings = function(rings, opt_extent) {
4212 var extent = ol.extent.createOrUpdateEmpty(opt_extent);
4213 return ol.extent.extendRings(extent, rings);
4214};
4215
4216
4217/**
4218 * Determine if two extents are equivalent.
4219 * @param {ol.Extent} extent1 Extent 1.
4220 * @param {ol.Extent} extent2 Extent 2.
4221 * @return {boolean} The two extents are equivalent.
4222 * @api
4223 */
4224ol.extent.equals = function(extent1, extent2) {
4225 return extent1[0] == extent2[0] && extent1[2] == extent2[2] &&
4226 extent1[1] == extent2[1] && extent1[3] == extent2[3];
4227};
4228
4229
4230/**
4231 * Modify an extent to include another extent.
4232 * @param {ol.Extent} extent1 The extent to be modified.
4233 * @param {ol.Extent} extent2 The extent that will be included in the first.
4234 * @return {ol.Extent} A reference to the first (extended) extent.
4235 * @api
4236 */
4237ol.extent.extend = function(extent1, extent2) {
4238 if (extent2[0] < extent1[0]) {
4239 extent1[0] = extent2[0];
4240 }
4241 if (extent2[2] > extent1[2]) {
4242 extent1[2] = extent2[2];
4243 }
4244 if (extent2[1] < extent1[1]) {
4245 extent1[1] = extent2[1];
4246 }
4247 if (extent2[3] > extent1[3]) {
4248 extent1[3] = extent2[3];
4249 }
4250 return extent1;
4251};
4252
4253
4254/**
4255 * @param {ol.Extent} extent Extent.
4256 * @param {ol.Coordinate} coordinate Coordinate.
4257 */
4258ol.extent.extendCoordinate = function(extent, coordinate) {
4259 if (coordinate[0] < extent[0]) {
4260 extent[0] = coordinate[0];
4261 }
4262 if (coordinate[0] > extent[2]) {
4263 extent[2] = coordinate[0];
4264 }
4265 if (coordinate[1] < extent[1]) {
4266 extent[1] = coordinate[1];
4267 }
4268 if (coordinate[1] > extent[3]) {
4269 extent[3] = coordinate[1];
4270 }
4271};
4272
4273
4274/**
4275 * @param {ol.Extent} extent Extent.
4276 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
4277 * @return {ol.Extent} Extent.
4278 */
4279ol.extent.extendCoordinates = function(extent, coordinates) {
4280 var i, ii;
4281 for (i = 0, ii = coordinates.length; i < ii; ++i) {
4282 ol.extent.extendCoordinate(extent, coordinates[i]);
4283 }
4284 return extent;
4285};
4286
4287
4288/**
4289 * @param {ol.Extent} extent Extent.
4290 * @param {Array.<number>} flatCoordinates Flat coordinates.
4291 * @param {number} offset Offset.
4292 * @param {number} end End.
4293 * @param {number} stride Stride.
4294 * @return {ol.Extent} Extent.
4295 */
4296ol.extent.extendFlatCoordinates = function(extent, flatCoordinates, offset, end, stride) {
4297 for (; offset < end; offset += stride) {
4298 ol.extent.extendXY(
4299 extent, flatCoordinates[offset], flatCoordinates[offset + 1]);
4300 }
4301 return extent;
4302};
4303
4304
4305/**
4306 * @param {ol.Extent} extent Extent.
4307 * @param {Array.<Array.<ol.Coordinate>>} rings Rings.
4308 * @return {ol.Extent} Extent.
4309 */
4310ol.extent.extendRings = function(extent, rings) {
4311 var i, ii;
4312 for (i = 0, ii = rings.length; i < ii; ++i) {
4313 ol.extent.extendCoordinates(extent, rings[i]);
4314 }
4315 return extent;
4316};
4317
4318
4319/**
4320 * @param {ol.Extent} extent Extent.
4321 * @param {number} x X.
4322 * @param {number} y Y.
4323 */
4324ol.extent.extendXY = function(extent, x, y) {
4325 extent[0] = Math.min(extent[0], x);
4326 extent[1] = Math.min(extent[1], y);
4327 extent[2] = Math.max(extent[2], x);
4328 extent[3] = Math.max(extent[3], y);
4329};
4330
4331
4332/**
4333 * This function calls `callback` for each corner of the extent. If the
4334 * callback returns a truthy value the function returns that value
4335 * immediately. Otherwise the function returns `false`.
4336 * @param {ol.Extent} extent Extent.
4337 * @param {function(this:T, ol.Coordinate): S} callback Callback.
4338 * @param {T=} opt_this Value to use as `this` when executing `callback`.
4339 * @return {S|boolean} Value.
4340 * @template S, T
4341 */
4342ol.extent.forEachCorner = function(extent, callback, opt_this) {
4343 var val;
4344 val = callback.call(opt_this, ol.extent.getBottomLeft(extent));
4345 if (val) {
4346 return val;
4347 }
4348 val = callback.call(opt_this, ol.extent.getBottomRight(extent));
4349 if (val) {
4350 return val;
4351 }
4352 val = callback.call(opt_this, ol.extent.getTopRight(extent));
4353 if (val) {
4354 return val;
4355 }
4356 val = callback.call(opt_this, ol.extent.getTopLeft(extent));
4357 if (val) {
4358 return val;
4359 }
4360 return false;
4361};
4362
4363
4364/**
4365 * Get the size of an extent.
4366 * @param {ol.Extent} extent Extent.
4367 * @return {number} Area.
4368 * @api
4369 */
4370ol.extent.getArea = function(extent) {
4371 var area = 0;
4372 if (!ol.extent.isEmpty(extent)) {
4373 area = ol.extent.getWidth(extent) * ol.extent.getHeight(extent);
4374 }
4375 return area;
4376};
4377
4378
4379/**
4380 * Get the bottom left coordinate of an extent.
4381 * @param {ol.Extent} extent Extent.
4382 * @return {ol.Coordinate} Bottom left coordinate.
4383 * @api
4384 */
4385ol.extent.getBottomLeft = function(extent) {
4386 return [extent[0], extent[1]];
4387};
4388
4389
4390/**
4391 * Get the bottom right coordinate of an extent.
4392 * @param {ol.Extent} extent Extent.
4393 * @return {ol.Coordinate} Bottom right coordinate.
4394 * @api
4395 */
4396ol.extent.getBottomRight = function(extent) {
4397 return [extent[2], extent[1]];
4398};
4399
4400
4401/**
4402 * Get the center coordinate of an extent.
4403 * @param {ol.Extent} extent Extent.
4404 * @return {ol.Coordinate} Center.
4405 * @api
4406 */
4407ol.extent.getCenter = function(extent) {
4408 return [(extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2];
4409};
4410
4411
4412/**
4413 * Get a corner coordinate of an extent.
4414 * @param {ol.Extent} extent Extent.
4415 * @param {ol.extent.Corner} corner Corner.
4416 * @return {ol.Coordinate} Corner coordinate.
4417 */
4418ol.extent.getCorner = function(extent, corner) {
4419 var coordinate;
4420 if (corner === ol.extent.Corner.BOTTOM_LEFT) {
4421 coordinate = ol.extent.getBottomLeft(extent);
4422 } else if (corner === ol.extent.Corner.BOTTOM_RIGHT) {
4423 coordinate = ol.extent.getBottomRight(extent);
4424 } else if (corner === ol.extent.Corner.TOP_LEFT) {
4425 coordinate = ol.extent.getTopLeft(extent);
4426 } else if (corner === ol.extent.Corner.TOP_RIGHT) {
4427 coordinate = ol.extent.getTopRight(extent);
4428 } else {
4429 ol.asserts.assert(false, 13); // Invalid corner
4430 }
4431 return /** @type {!ol.Coordinate} */ (coordinate);
4432};
4433
4434
4435/**
4436 * @param {ol.Extent} extent1 Extent 1.
4437 * @param {ol.Extent} extent2 Extent 2.
4438 * @return {number} Enlarged area.
4439 */
4440ol.extent.getEnlargedArea = function(extent1, extent2) {
4441 var minX = Math.min(extent1[0], extent2[0]);
4442 var minY = Math.min(extent1[1], extent2[1]);
4443 var maxX = Math.max(extent1[2], extent2[2]);
4444 var maxY = Math.max(extent1[3], extent2[3]);
4445 return (maxX - minX) * (maxY - minY);
4446};
4447
4448
4449/**
4450 * @param {ol.Coordinate} center Center.
4451 * @param {number} resolution Resolution.
4452 * @param {number} rotation Rotation.
4453 * @param {ol.Size} size Size.
4454 * @param {ol.Extent=} opt_extent Destination extent.
4455 * @return {ol.Extent} Extent.
4456 */
4457ol.extent.getForViewAndSize = function(center, resolution, rotation, size, opt_extent) {
4458 var dx = resolution * size[0] / 2;
4459 var dy = resolution * size[1] / 2;
4460 var cosRotation = Math.cos(rotation);
4461 var sinRotation = Math.sin(rotation);
4462 var xCos = dx * cosRotation;
4463 var xSin = dx * sinRotation;
4464 var yCos = dy * cosRotation;
4465 var ySin = dy * sinRotation;
4466 var x = center[0];
4467 var y = center[1];
4468 var x0 = x - xCos + ySin;
4469 var x1 = x - xCos - ySin;
4470 var x2 = x + xCos - ySin;
4471 var x3 = x + xCos + ySin;
4472 var y0 = y - xSin - yCos;
4473 var y1 = y - xSin + yCos;
4474 var y2 = y + xSin + yCos;
4475 var y3 = y + xSin - yCos;
4476 return ol.extent.createOrUpdate(
4477 Math.min(x0, x1, x2, x3), Math.min(y0, y1, y2, y3),
4478 Math.max(x0, x1, x2, x3), Math.max(y0, y1, y2, y3),
4479 opt_extent);
4480};
4481
4482
4483/**
4484 * Get the height of an extent.
4485 * @param {ol.Extent} extent Extent.
4486 * @return {number} Height.
4487 * @api
4488 */
4489ol.extent.getHeight = function(extent) {
4490 return extent[3] - extent[1];
4491};
4492
4493
4494/**
4495 * @param {ol.Extent} extent1 Extent 1.
4496 * @param {ol.Extent} extent2 Extent 2.
4497 * @return {number} Intersection area.
4498 */
4499ol.extent.getIntersectionArea = function(extent1, extent2) {
4500 var intersection = ol.extent.getIntersection(extent1, extent2);
4501 return ol.extent.getArea(intersection);
4502};
4503
4504
4505/**
4506 * Get the intersection of two extents.
4507 * @param {ol.Extent} extent1 Extent 1.
4508 * @param {ol.Extent} extent2 Extent 2.
4509 * @param {ol.Extent=} opt_extent Optional extent to populate with intersection.
4510 * @return {ol.Extent} Intersecting extent.
4511 * @api
4512 */
4513ol.extent.getIntersection = function(extent1, extent2, opt_extent) {
4514 var intersection = opt_extent ? opt_extent : ol.extent.createEmpty();
4515 if (ol.extent.intersects(extent1, extent2)) {
4516 if (extent1[0] > extent2[0]) {
4517 intersection[0] = extent1[0];
4518 } else {
4519 intersection[0] = extent2[0];
4520 }
4521 if (extent1[1] > extent2[1]) {
4522 intersection[1] = extent1[1];
4523 } else {
4524 intersection[1] = extent2[1];
4525 }
4526 if (extent1[2] < extent2[2]) {
4527 intersection[2] = extent1[2];
4528 } else {
4529 intersection[2] = extent2[2];
4530 }
4531 if (extent1[3] < extent2[3]) {
4532 intersection[3] = extent1[3];
4533 } else {
4534 intersection[3] = extent2[3];
4535 }
4536 }
4537 return intersection;
4538};
4539
4540
4541/**
4542 * @param {ol.Extent} extent Extent.
4543 * @return {number} Margin.
4544 */
4545ol.extent.getMargin = function(extent) {
4546 return ol.extent.getWidth(extent) + ol.extent.getHeight(extent);
4547};
4548
4549
4550/**
4551 * Get the size (width, height) of an extent.
4552 * @param {ol.Extent} extent The extent.
4553 * @return {ol.Size} The extent size.
4554 * @api
4555 */
4556ol.extent.getSize = function(extent) {
4557 return [extent[2] - extent[0], extent[3] - extent[1]];
4558};
4559
4560
4561/**
4562 * Get the top left coordinate of an extent.
4563 * @param {ol.Extent} extent Extent.
4564 * @return {ol.Coordinate} Top left coordinate.
4565 * @api
4566 */
4567ol.extent.getTopLeft = function(extent) {
4568 return [extent[0], extent[3]];
4569};
4570
4571
4572/**
4573 * Get the top right coordinate of an extent.
4574 * @param {ol.Extent} extent Extent.
4575 * @return {ol.Coordinate} Top right coordinate.
4576 * @api
4577 */
4578ol.extent.getTopRight = function(extent) {
4579 return [extent[2], extent[3]];
4580};
4581
4582
4583/**
4584 * Get the width of an extent.
4585 * @param {ol.Extent} extent Extent.
4586 * @return {number} Width.
4587 * @api
4588 */
4589ol.extent.getWidth = function(extent) {
4590 return extent[2] - extent[0];
4591};
4592
4593
4594/**
4595 * Determine if one extent intersects another.
4596 * @param {ol.Extent} extent1 Extent 1.
4597 * @param {ol.Extent} extent2 Extent.
4598 * @return {boolean} The two extents intersect.
4599 * @api
4600 */
4601ol.extent.intersects = function(extent1, extent2) {
4602 return extent1[0] <= extent2[2] &&
4603 extent1[2] >= extent2[0] &&
4604 extent1[1] <= extent2[3] &&
4605 extent1[3] >= extent2[1];
4606};
4607
4608
4609/**
4610 * Determine if an extent is empty.
4611 * @param {ol.Extent} extent Extent.
4612 * @return {boolean} Is empty.
4613 * @api
4614 */
4615ol.extent.isEmpty = function(extent) {
4616 return extent[2] < extent[0] || extent[3] < extent[1];
4617};
4618
4619
4620/**
4621 * @param {ol.Extent} extent Extent.
4622 * @param {ol.Extent=} opt_extent Extent.
4623 * @return {ol.Extent} Extent.
4624 */
4625ol.extent.returnOrUpdate = function(extent, opt_extent) {
4626 if (opt_extent) {
4627 opt_extent[0] = extent[0];
4628 opt_extent[1] = extent[1];
4629 opt_extent[2] = extent[2];
4630 opt_extent[3] = extent[3];
4631 return opt_extent;
4632 } else {
4633 return extent;
4634 }
4635};
4636
4637
4638/**
4639 * @param {ol.Extent} extent Extent.
4640 * @param {number} value Value.
4641 */
4642ol.extent.scaleFromCenter = function(extent, value) {
4643 var deltaX = ((extent[2] - extent[0]) / 2) * (value - 1);
4644 var deltaY = ((extent[3] - extent[1]) / 2) * (value - 1);
4645 extent[0] -= deltaX;
4646 extent[2] += deltaX;
4647 extent[1] -= deltaY;
4648 extent[3] += deltaY;
4649};
4650
4651
4652/**
4653 * Determine if the segment between two coordinates intersects (crosses,
4654 * touches, or is contained by) the provided extent.
4655 * @param {ol.Extent} extent The extent.
4656 * @param {ol.Coordinate} start Segment start coordinate.
4657 * @param {ol.Coordinate} end Segment end coordinate.
4658 * @return {boolean} The segment intersects the extent.
4659 */
4660ol.extent.intersectsSegment = function(extent, start, end) {
4661 var intersects = false;
4662 var startRel = ol.extent.coordinateRelationship(extent, start);
4663 var endRel = ol.extent.coordinateRelationship(extent, end);
4664 if (startRel === ol.extent.Relationship.INTERSECTING ||
4665 endRel === ol.extent.Relationship.INTERSECTING) {
4666 intersects = true;
4667 } else {
4668 var minX = extent[0];
4669 var minY = extent[1];
4670 var maxX = extent[2];
4671 var maxY = extent[3];
4672 var startX = start[0];
4673 var startY = start[1];
4674 var endX = end[0];
4675 var endY = end[1];
4676 var slope = (endY - startY) / (endX - startX);
4677 var x, y;
4678 if (!!(endRel & ol.extent.Relationship.ABOVE) &&
4679 !(startRel & ol.extent.Relationship.ABOVE)) {
4680 // potentially intersects top
4681 x = endX - ((endY - maxY) / slope);
4682 intersects = x >= minX && x <= maxX;
4683 }
4684 if (!intersects && !!(endRel & ol.extent.Relationship.RIGHT) &&
4685 !(startRel & ol.extent.Relationship.RIGHT)) {
4686 // potentially intersects right
4687 y = endY - ((endX - maxX) * slope);
4688 intersects = y >= minY && y <= maxY;
4689 }
4690 if (!intersects && !!(endRel & ol.extent.Relationship.BELOW) &&
4691 !(startRel & ol.extent.Relationship.BELOW)) {
4692 // potentially intersects bottom
4693 x = endX - ((endY - minY) / slope);
4694 intersects = x >= minX && x <= maxX;
4695 }
4696 if (!intersects && !!(endRel & ol.extent.Relationship.LEFT) &&
4697 !(startRel & ol.extent.Relationship.LEFT)) {
4698 // potentially intersects left
4699 y = endY - ((endX - minX) * slope);
4700 intersects = y >= minY && y <= maxY;
4701 }
4702
4703 }
4704 return intersects;
4705};
4706
4707
4708/**
4709 * Apply a transform function to the extent.
4710 * @param {ol.Extent} extent Extent.
4711 * @param {ol.TransformFunction} transformFn Transform function. Called with
4712 * [minX, minY, maxX, maxY] extent coordinates.
4713 * @param {ol.Extent=} opt_extent Destination extent.
4714 * @return {ol.Extent} Extent.
4715 * @api
4716 */
4717ol.extent.applyTransform = function(extent, transformFn, opt_extent) {
4718 var coordinates = [
4719 extent[0], extent[1],
4720 extent[0], extent[3],
4721 extent[2], extent[1],
4722 extent[2], extent[3]
4723 ];
4724 transformFn(coordinates, coordinates, 2);
4725 var xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
4726 var ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
4727 return ol.extent.boundingExtentXYs_(xs, ys, opt_extent);
4728};
4729
4730goog.provide('ol.obj');
4731
4732
4733/**
4734 * Polyfill for Object.assign(). Assigns enumerable and own properties from
4735 * one or more source objects to a target object.
4736 *
4737 * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
4738 * @param {!Object} target The target object.
4739 * @param {...Object} var_sources The source object(s).
4740 * @return {!Object} The modified target object.
4741 */
4742ol.obj.assign = (typeof Object.assign === 'function') ? Object.assign : function(target, var_sources) {
4743 if (target === undefined || target === null) {
4744 throw new TypeError('Cannot convert undefined or null to object');
4745 }
4746
4747 var output = Object(target);
4748 for (var i = 1, ii = arguments.length; i < ii; ++i) {
4749 var source = arguments[i];
4750 if (source !== undefined && source !== null) {
4751 for (var key in source) {
4752 if (source.hasOwnProperty(key)) {
4753 output[key] = source[key];
4754 }
4755 }
4756 }
4757 }
4758 return output;
4759};
4760
4761
4762/**
4763 * Removes all properties from an object.
4764 * @param {Object} object The object to clear.
4765 */
4766ol.obj.clear = function(object) {
4767 for (var property in object) {
4768 delete object[property];
4769 }
4770};
4771
4772
4773/**
4774 * Get an array of property values from an object.
4775 * @param {Object<K,V>} object The object from which to get the values.
4776 * @return {!Array<V>} The property values.
4777 * @template K,V
4778 */
4779ol.obj.getValues = function(object) {
4780 var values = [];
4781 for (var property in object) {
4782 values.push(object[property]);
4783 }
4784 return values;
4785};
4786
4787
4788/**
4789 * Determine if an object has any properties.
4790 * @param {Object} object The object to check.
4791 * @return {boolean} The object is empty.
4792 */
4793ol.obj.isEmpty = function(object) {
4794 var property;
4795 for (property in object) {
4796 return false;
4797 }
4798 return !property;
4799};
4800
4801goog.provide('ol.geom.GeometryType');
4802
4803
4804/**
4805 * The geometry type. One of `'Point'`, `'LineString'`, `'LinearRing'`,
4806 * `'Polygon'`, `'MultiPoint'`, `'MultiLineString'`, `'MultiPolygon'`,
4807 * `'GeometryCollection'`, `'Circle'`.
4808 * @enum {string}
4809 */
4810ol.geom.GeometryType = {
4811 POINT: 'Point',
4812 LINE_STRING: 'LineString',
4813 LINEAR_RING: 'LinearRing',
4814 POLYGON: 'Polygon',
4815 MULTI_POINT: 'MultiPoint',
4816 MULTI_LINE_STRING: 'MultiLineString',
4817 MULTI_POLYGON: 'MultiPolygon',
4818 GEOMETRY_COLLECTION: 'GeometryCollection',
4819 CIRCLE: 'Circle'
4820};
4821
4822/**
4823 * @license
4824 * Latitude/longitude spherical geodesy formulae taken from
4825 * http://www.movable-type.co.uk/scripts/latlong.html
4826 * Licensed under CC-BY-3.0.
4827 */
4828
4829goog.provide('ol.Sphere');
4830
4831goog.require('ol.math');
4832goog.require('ol.geom.GeometryType');
4833
4834
4835/**
4836 * @classdesc
4837 * Class to create objects that can be used with {@link
4838 * ol.geom.Polygon.circular}.
4839 *
4840 * For example to create a sphere whose radius is equal to the semi-major
4841 * axis of the WGS84 ellipsoid:
4842 *
4843 * ```js
4844 * var wgs84Sphere= new ol.Sphere(6378137);
4845 * ```
4846 *
4847 * @constructor
4848 * @param {number} radius Radius.
4849 * @api
4850 */
4851ol.Sphere = function(radius) {
4852
4853 /**
4854 * @type {number}
4855 */
4856 this.radius = radius;
4857
4858};
4859
4860
4861/**
4862 * Returns the geodesic area for a list of coordinates.
4863 *
4864 * [Reference](https://trs-new.jpl.nasa.gov/handle/2014/40409)
4865 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
4866 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
4867 * Laboratory, Pasadena, CA, June 2007
4868 *
4869 * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear
4870 * ring. If the ring is oriented clockwise, the area will be positive,
4871 * otherwise it will be negative.
4872 * @return {number} Area.
4873 * @api
4874 */
4875ol.Sphere.prototype.geodesicArea = function(coordinates) {
4876 return ol.Sphere.getArea_(coordinates, this.radius);
4877};
4878
4879
4880/**
4881 * Returns the distance from c1 to c2 using the haversine formula.
4882 *
4883 * @param {ol.Coordinate} c1 Coordinate 1.
4884 * @param {ol.Coordinate} c2 Coordinate 2.
4885 * @return {number} Haversine distance.
4886 * @api
4887 */
4888ol.Sphere.prototype.haversineDistance = function(c1, c2) {
4889 return ol.Sphere.getDistance_(c1, c2, this.radius);
4890};
4891
4892
4893/**
4894 * Returns the coordinate at the given distance and bearing from `c1`.
4895 *
4896 * @param {ol.Coordinate} c1 The origin point (`[lon, lat]` in degrees).
4897 * @param {number} distance The great-circle distance between the origin
4898 * point and the target point.
4899 * @param {number} bearing The bearing (in radians).
4900 * @return {ol.Coordinate} The target point.
4901 */
4902ol.Sphere.prototype.offset = function(c1, distance, bearing) {
4903 var lat1 = ol.math.toRadians(c1[1]);
4904 var lon1 = ol.math.toRadians(c1[0]);
4905 var dByR = distance / this.radius;
4906 var lat = Math.asin(
4907 Math.sin(lat1) * Math.cos(dByR) +
4908 Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
4909 var lon = lon1 + Math.atan2(
4910 Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1),
4911 Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
4912 return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];
4913};
4914
4915
4916/**
4917 * The mean Earth radius (1/3 * (2a + b)) for the WGS84 ellipsoid.
4918 * https://en.wikipedia.org/wiki/Earth_radius#Mean_radius
4919 * @type {number}
4920 */
4921ol.Sphere.DEFAULT_RADIUS = 6371008.8;
4922
4923
4924/**
4925 * Get the spherical length of a geometry. This length is the sum of the
4926 * great circle distances between coordinates. For polygons, the length is
4927 * the sum of all rings. For points, the length is zero. For multi-part
4928 * geometries, the length is the sum of the length of each part.
4929 * @param {ol.geom.Geometry} geometry A geometry.
4930 * @param {olx.SphereMetricOptions=} opt_options Options for the length
4931 * calculation. By default, geometries are assumed to be in 'EPSG:3857'.
4932 * You can change this by providing a `projection` option.
4933 * @return {number} The spherical length (in meters).
4934 * @api
4935 */
4936ol.Sphere.getLength = function(geometry, opt_options) {
4937 var options = opt_options || {};
4938 var radius = options.radius || ol.Sphere.DEFAULT_RADIUS;
4939 var projection = options.projection || 'EPSG:3857';
4940 geometry = geometry.clone().transform(projection, 'EPSG:4326');
4941 var type = geometry.getType();
4942 var length = 0;
4943 var coordinates, coords, i, ii, j, jj;
4944 switch (type) {
4945 case ol.geom.GeometryType.POINT:
4946 case ol.geom.GeometryType.MULTI_POINT: {
4947 break;
4948 }
4949 case ol.geom.GeometryType.LINE_STRING:
4950 case ol.geom.GeometryType.LINEAR_RING: {
4951 coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
4952 length = ol.Sphere.getLength_(coordinates, radius);
4953 break;
4954 }
4955 case ol.geom.GeometryType.MULTI_LINE_STRING:
4956 case ol.geom.GeometryType.POLYGON: {
4957 coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
4958 for (i = 0, ii = coordinates.length; i < ii; ++i) {
4959 length += ol.Sphere.getLength_(coordinates[i], radius);
4960 }
4961 break;
4962 }
4963 case ol.geom.GeometryType.MULTI_POLYGON: {
4964 coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
4965 for (i = 0, ii = coordinates.length; i < ii; ++i) {
4966 coords = coordinates[i];
4967 for (j = 0, jj = coords.length; j < jj; ++j) {
4968 length += ol.Sphere.getLength_(coords[j], radius);
4969 }
4970 }
4971 break;
4972 }
4973 case ol.geom.GeometryType.GEOMETRY_COLLECTION: {
4974 var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();
4975 for (i = 0, ii = geometries.length; i < ii; ++i) {
4976 length += ol.Sphere.getLength(geometries[i], opt_options);
4977 }
4978 break;
4979 }
4980 default: {
4981 throw new Error('Unsupported geometry type: ' + type);
4982 }
4983 }
4984 return length;
4985};
4986
4987
4988/**
4989 * Get the cumulative great circle length of linestring coordinates (geographic).
4990 * @param {Array} coordinates Linestring coordinates.
4991 * @param {number} radius The sphere radius to use.
4992 * @return {number} The length (in meters).
4993 */
4994ol.Sphere.getLength_ = function(coordinates, radius) {
4995 var length = 0;
4996 for (var i = 0, ii = coordinates.length; i < ii - 1; ++i) {
4997 length += ol.Sphere.getDistance_(coordinates[i], coordinates[i + 1], radius);
4998 }
4999 return length;
5000};
5001
5002
5003/**
5004 * Get the great circle distance between two geographic coordinates.
5005 * @param {Array} c1 Starting coordinate.
5006 * @param {Array} c2 Ending coordinate.
5007 * @param {number} radius The sphere radius to use.
5008 * @return {number} The great circle distance between the points (in meters).
5009 */
5010ol.Sphere.getDistance_ = function(c1, c2, radius) {
5011 var lat1 = ol.math.toRadians(c1[1]);
5012 var lat2 = ol.math.toRadians(c2[1]);
5013 var deltaLatBy2 = (lat2 - lat1) / 2;
5014 var deltaLonBy2 = ol.math.toRadians(c2[0] - c1[0]) / 2;
5015 var a = Math.sin(deltaLatBy2) * Math.sin(deltaLatBy2) +
5016 Math.sin(deltaLonBy2) * Math.sin(deltaLonBy2) *
5017 Math.cos(lat1) * Math.cos(lat2);
5018 return 2 * radius * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
5019};
5020
5021
5022/**
5023 * Get the spherical area of a geometry. This is the area (in meters) assuming
5024 * that polygon edges are segments of great circles on a sphere.
5025 * @param {ol.geom.Geometry} geometry A geometry.
5026 * @param {olx.SphereMetricOptions=} opt_options Options for the area
5027 * calculation. By default, geometries are assumed to be in 'EPSG:3857'.
5028 * You can change this by providing a `projection` option.
5029 * @return {number} The spherical area (in square meters).
5030 * @api
5031 */
5032ol.Sphere.getArea = function(geometry, opt_options) {
5033 var options = opt_options || {};
5034 var radius = options.radius || ol.Sphere.DEFAULT_RADIUS;
5035 var projection = options.projection || 'EPSG:3857';
5036 geometry = geometry.clone().transform(projection, 'EPSG:4326');
5037 var type = geometry.getType();
5038 var area = 0;
5039 var coordinates, coords, i, ii, j, jj;
5040 switch (type) {
5041 case ol.geom.GeometryType.POINT:
5042 case ol.geom.GeometryType.MULTI_POINT:
5043 case ol.geom.GeometryType.LINE_STRING:
5044 case ol.geom.GeometryType.MULTI_LINE_STRING:
5045 case ol.geom.GeometryType.LINEAR_RING: {
5046 break;
5047 }
5048 case ol.geom.GeometryType.POLYGON: {
5049 coordinates = /** @type {ol.geom.Polygon} */ (geometry).getCoordinates();
5050 area = Math.abs(ol.Sphere.getArea_(coordinates[0], radius));
5051 for (i = 1, ii = coordinates.length; i < ii; ++i) {
5052 area -= Math.abs(ol.Sphere.getArea_(coordinates[i], radius));
5053 }
5054 break;
5055 }
5056 case ol.geom.GeometryType.MULTI_POLYGON: {
5057 coordinates = /** @type {ol.geom.SimpleGeometry} */ (geometry).getCoordinates();
5058 for (i = 0, ii = coordinates.length; i < ii; ++i) {
5059 coords = coordinates[i];
5060 area += Math.abs(ol.Sphere.getArea_(coords[0], radius));
5061 for (j = 1, jj = coords.length; j < jj; ++j) {
5062 area -= Math.abs(ol.Sphere.getArea_(coords[j], radius));
5063 }
5064 }
5065 break;
5066 }
5067 case ol.geom.GeometryType.GEOMETRY_COLLECTION: {
5068 var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();
5069 for (i = 0, ii = geometries.length; i < ii; ++i) {
5070 area += ol.Sphere.getArea(geometries[i], opt_options);
5071 }
5072 break;
5073 }
5074 default: {
5075 throw new Error('Unsupported geometry type: ' + type);
5076 }
5077 }
5078 return area;
5079};
5080
5081
5082/**
5083 * Returns the spherical area for a list of coordinates.
5084 *
5085 * [Reference](https://trs-new.jpl.nasa.gov/handle/2014/40409)
5086 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
5087 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
5088 * Laboratory, Pasadena, CA, June 2007
5089 *
5090 * @param {Array.<ol.Coordinate>} coordinates List of coordinates of a linear
5091 * ring. If the ring is oriented clockwise, the area will be positive,
5092 * otherwise it will be negative.
5093 * @param {number} radius The sphere radius.
5094 * @return {number} Area (in square meters).
5095 */
5096ol.Sphere.getArea_ = function(coordinates, radius) {
5097 var area = 0, len = coordinates.length;
5098 var x1 = coordinates[len - 1][0];
5099 var y1 = coordinates[len - 1][1];
5100 for (var i = 0; i < len; i++) {
5101 var x2 = coordinates[i][0], y2 = coordinates[i][1];
5102 area += ol.math.toRadians(x2 - x1) *
5103 (2 + Math.sin(ol.math.toRadians(y1)) +
5104 Math.sin(ol.math.toRadians(y2)));
5105 x1 = x2;
5106 y1 = y2;
5107 }
5108 return area * radius * radius / 2.0;
5109};
5110
5111goog.provide('ol.proj.Units');
5112
5113
5114/**
5115 * Projection units: `'degrees'`, `'ft'`, `'m'`, `'pixels'`, `'tile-pixels'` or
5116 * `'us-ft'`.
5117 * @enum {string}
5118 */
5119ol.proj.Units = {
5120 DEGREES: 'degrees',
5121 FEET: 'ft',
5122 METERS: 'm',
5123 PIXELS: 'pixels',
5124 TILE_PIXELS: 'tile-pixels',
5125 USFEET: 'us-ft'
5126};
5127
5128
5129/**
5130 * Meters per unit lookup table.
5131 * @const
5132 * @type {Object.<ol.proj.Units, number>}
5133 * @api
5134 */
5135ol.proj.Units.METERS_PER_UNIT = {};
5136// use the radius of the Normal sphere
5137ol.proj.Units.METERS_PER_UNIT[ol.proj.Units.DEGREES] =
5138 2 * Math.PI * 6370997 / 360;
5139ol.proj.Units.METERS_PER_UNIT[ol.proj.Units.FEET] = 0.3048;
5140ol.proj.Units.METERS_PER_UNIT[ol.proj.Units.METERS] = 1;
5141ol.proj.Units.METERS_PER_UNIT[ol.proj.Units.USFEET] = 1200 / 3937;
5142
5143goog.provide('ol.proj.proj4');
5144
5145
5146/**
5147 * @private
5148 * @type {Proj4}
5149 */
5150ol.proj.proj4.cache_ = null;
5151
5152
5153/**
5154 * Store the proj4 function.
5155 * @param {Proj4} proj4 The proj4 function.
5156 */
5157ol.proj.proj4.set = function(proj4) {
5158 ol.proj.proj4.cache_ = proj4;
5159};
5160
5161
5162/**
5163 * Get proj4.
5164 * @return {Proj4} The proj4 function set above or available globally.
5165 */
5166ol.proj.proj4.get = function() {
5167 return ol.proj.proj4.cache_ || window['proj4'];
5168};
5169
5170goog.provide('ol.proj.Projection');
5171
5172goog.require('ol');
5173goog.require('ol.proj.Units');
5174goog.require('ol.proj.proj4');
5175
5176
5177/**
5178 * @classdesc
5179 * Projection definition class. One of these is created for each projection
5180 * supported in the application and stored in the {@link ol.proj} namespace.
5181 * You can use these in applications, but this is not required, as API params
5182 * and options use {@link ol.ProjectionLike} which means the simple string
5183 * code will suffice.
5184 *
5185 * You can use {@link ol.proj.get} to retrieve the object for a particular
5186 * projection.
5187 *
5188 * The library includes definitions for `EPSG:4326` and `EPSG:3857`, together
5189 * with the following aliases:
5190 * * `EPSG:4326`: CRS:84, urn:ogc:def:crs:EPSG:6.6:4326,
5191 * urn:ogc:def:crs:OGC:1.3:CRS84, urn:ogc:def:crs:OGC:2:84,
5192 * http://www.opengis.net/gml/srs/epsg.xml#4326,
5193 * urn:x-ogc:def:crs:EPSG:4326
5194 * * `EPSG:3857`: EPSG:102100, EPSG:102113, EPSG:900913,
5195 * urn:ogc:def:crs:EPSG:6.18:3:3857,
5196 * http://www.opengis.net/gml/srs/epsg.xml#3857
5197 *
5198 * If you use proj4js, aliases can be added using `proj4.defs()`; see
5199 * [documentation](https://github.com/proj4js/proj4js). To set an alternative
5200 * namespace for proj4, use {@link ol.proj.setProj4}.
5201 *
5202 * @constructor
5203 * @param {olx.ProjectionOptions} options Projection options.
5204 * @struct
5205 * @api
5206 */
5207ol.proj.Projection = function(options) {
5208 /**
5209 * @private
5210 * @type {string}
5211 */
5212 this.code_ = options.code;
5213
5214 /**
5215 * @private
5216 * @type {ol.proj.Units}
5217 */
5218 this.units_ = /** @type {ol.proj.Units} */ (options.units);
5219
5220 /**
5221 * @private
5222 * @type {ol.Extent}
5223 */
5224 this.extent_ = options.extent !== undefined ? options.extent : null;
5225
5226 /**
5227 * @private
5228 * @type {ol.Extent}
5229 */
5230 this.worldExtent_ = options.worldExtent !== undefined ?
5231 options.worldExtent : null;
5232
5233 /**
5234 * @private
5235 * @type {string}
5236 */
5237 this.axisOrientation_ = options.axisOrientation !== undefined ?
5238 options.axisOrientation : 'enu';
5239
5240 /**
5241 * @private
5242 * @type {boolean}
5243 */
5244 this.global_ = options.global !== undefined ? options.global : false;
5245
5246 /**
5247 * @private
5248 * @type {boolean}
5249 */
5250 this.canWrapX_ = !!(this.global_ && this.extent_);
5251
5252 /**
5253 * @private
5254 * @type {function(number, ol.Coordinate):number|undefined}
5255 */
5256 this.getPointResolutionFunc_ = options.getPointResolution;
5257
5258 /**
5259 * @private
5260 * @type {ol.tilegrid.TileGrid}
5261 */
5262 this.defaultTileGrid_ = null;
5263
5264 /**
5265 * @private
5266 * @type {number|undefined}
5267 */
5268 this.metersPerUnit_ = options.metersPerUnit;
5269
5270 var code = options.code;
5271 if (ol.ENABLE_PROJ4JS) {
5272 var proj4js = ol.proj.proj4.get();
5273 if (typeof proj4js == 'function') {
5274 var def = proj4js.defs(code);
5275 if (def !== undefined) {
5276 if (def.axis !== undefined && options.axisOrientation === undefined) {
5277 this.axisOrientation_ = def.axis;
5278 }
5279 if (options.metersPerUnit === undefined) {
5280 this.metersPerUnit_ = def.to_meter;
5281 }
5282 if (options.units === undefined) {
5283 this.units_ = def.units;
5284 }
5285 }
5286 }
5287 }
5288};
5289
5290
5291/**
5292 * @return {boolean} The projection is suitable for wrapping the x-axis
5293 */
5294ol.proj.Projection.prototype.canWrapX = function() {
5295 return this.canWrapX_;
5296};
5297
5298
5299/**
5300 * Get the code for this projection, e.g. 'EPSG:4326'.
5301 * @return {string} Code.
5302 * @api
5303 */
5304ol.proj.Projection.prototype.getCode = function() {
5305 return this.code_;
5306};
5307
5308
5309/**
5310 * Get the validity extent for this projection.
5311 * @return {ol.Extent} Extent.
5312 * @api
5313 */
5314ol.proj.Projection.prototype.getExtent = function() {
5315 return this.extent_;
5316};
5317
5318
5319/**
5320 * Get the units of this projection.
5321 * @return {ol.proj.Units} Units.
5322 * @api
5323 */
5324ol.proj.Projection.prototype.getUnits = function() {
5325 return this.units_;
5326};
5327
5328
5329/**
5330 * Get the amount of meters per unit of this projection. If the projection is
5331 * not configured with `metersPerUnit` or a units identifier, the return is
5332 * `undefined`.
5333 * @return {number|undefined} Meters.
5334 * @api
5335 */
5336ol.proj.Projection.prototype.getMetersPerUnit = function() {
5337 return this.metersPerUnit_ || ol.proj.Units.METERS_PER_UNIT[this.units_];
5338};
5339
5340
5341/**
5342 * Get the world extent for this projection.
5343 * @return {ol.Extent} Extent.
5344 * @api
5345 */
5346ol.proj.Projection.prototype.getWorldExtent = function() {
5347 return this.worldExtent_;
5348};
5349
5350
5351/**
5352 * Get the axis orientation of this projection.
5353 * Example values are:
5354 * enu - the default easting, northing, elevation.
5355 * neu - northing, easting, up - useful for "lat/long" geographic coordinates,
5356 * or south orientated transverse mercator.
5357 * wnu - westing, northing, up - some planetary coordinate systems have
5358 * "west positive" coordinate systems
5359 * @return {string} Axis orientation.
5360 */
5361ol.proj.Projection.prototype.getAxisOrientation = function() {
5362 return this.axisOrientation_;
5363};
5364
5365
5366/**
5367 * Is this projection a global projection which spans the whole world?
5368 * @return {boolean} Whether the projection is global.
5369 * @api
5370 */
5371ol.proj.Projection.prototype.isGlobal = function() {
5372 return this.global_;
5373};
5374
5375
5376/**
5377* Set if the projection is a global projection which spans the whole world
5378* @param {boolean} global Whether the projection is global.
5379* @api
5380*/
5381ol.proj.Projection.prototype.setGlobal = function(global) {
5382 this.global_ = global;
5383 this.canWrapX_ = !!(global && this.extent_);
5384};
5385
5386
5387/**
5388 * @return {ol.tilegrid.TileGrid} The default tile grid.
5389 */
5390ol.proj.Projection.prototype.getDefaultTileGrid = function() {
5391 return this.defaultTileGrid_;
5392};
5393
5394
5395/**
5396 * @param {ol.tilegrid.TileGrid} tileGrid The default tile grid.
5397 */
5398ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) {
5399 this.defaultTileGrid_ = tileGrid;
5400};
5401
5402
5403/**
5404 * Set the validity extent for this projection.
5405 * @param {ol.Extent} extent Extent.
5406 * @api
5407 */
5408ol.proj.Projection.prototype.setExtent = function(extent) {
5409 this.extent_ = extent;
5410 this.canWrapX_ = !!(this.global_ && extent);
5411};
5412
5413
5414/**
5415 * Set the world extent for this projection.
5416 * @param {ol.Extent} worldExtent World extent
5417 * [minlon, minlat, maxlon, maxlat].
5418 * @api
5419 */
5420ol.proj.Projection.prototype.setWorldExtent = function(worldExtent) {
5421 this.worldExtent_ = worldExtent;
5422};
5423
5424
5425/**
5426 * Set the getPointResolution function (see {@link ol.proj#getPointResolution}
5427 * for this projection.
5428 * @param {function(number, ol.Coordinate):number} func Function
5429 * @api
5430 */
5431ol.proj.Projection.prototype.setGetPointResolution = function(func) {
5432 this.getPointResolutionFunc_ = func;
5433};
5434
5435
5436/**
5437 * Get the custom point resolution function for this projection (if set).
5438 * @return {function(number, ol.Coordinate):number|undefined} The custom point
5439 * resolution function (if set).
5440 */
5441ol.proj.Projection.prototype.getPointResolutionFunc = function() {
5442 return this.getPointResolutionFunc_;
5443};
5444
5445goog.provide('ol.proj.EPSG3857');
5446
5447goog.require('ol');
5448goog.require('ol.math');
5449goog.require('ol.proj.Projection');
5450goog.require('ol.proj.Units');
5451
5452
5453/**
5454 * @classdesc
5455 * Projection object for web/spherical Mercator (EPSG:3857).
5456 *
5457 * @constructor
5458 * @extends {ol.proj.Projection}
5459 * @param {string} code Code.
5460 * @private
5461 */
5462ol.proj.EPSG3857.Projection_ = function(code) {
5463 ol.proj.Projection.call(this, {
5464 code: code,
5465 units: ol.proj.Units.METERS,
5466 extent: ol.proj.EPSG3857.EXTENT,
5467 global: true,
5468 worldExtent: ol.proj.EPSG3857.WORLD_EXTENT,
5469 getPointResolution: function(resolution, point) {
5470 return resolution / ol.math.cosh(point[1] / ol.proj.EPSG3857.RADIUS);
5471 }
5472 });
5473};
5474ol.inherits(ol.proj.EPSG3857.Projection_, ol.proj.Projection);
5475
5476
5477/**
5478 * Radius of WGS84 sphere
5479 *
5480 * @const
5481 * @type {number}
5482 */
5483ol.proj.EPSG3857.RADIUS = 6378137;
5484
5485
5486/**
5487 * @const
5488 * @type {number}
5489 */
5490ol.proj.EPSG3857.HALF_SIZE = Math.PI * ol.proj.EPSG3857.RADIUS;
5491
5492
5493/**
5494 * @const
5495 * @type {ol.Extent}
5496 */
5497ol.proj.EPSG3857.EXTENT = [
5498 -ol.proj.EPSG3857.HALF_SIZE, -ol.proj.EPSG3857.HALF_SIZE,
5499 ol.proj.EPSG3857.HALF_SIZE, ol.proj.EPSG3857.HALF_SIZE
5500];
5501
5502
5503/**
5504 * @const
5505 * @type {ol.Extent}
5506 */
5507ol.proj.EPSG3857.WORLD_EXTENT = [-180, -85, 180, 85];
5508
5509
5510/**
5511 * Projections equal to EPSG:3857.
5512 *
5513 * @const
5514 * @type {Array.<ol.proj.Projection>}
5515 */
5516ol.proj.EPSG3857.PROJECTIONS = [
5517 new ol.proj.EPSG3857.Projection_('EPSG:3857'),
5518 new ol.proj.EPSG3857.Projection_('EPSG:102100'),
5519 new ol.proj.EPSG3857.Projection_('EPSG:102113'),
5520 new ol.proj.EPSG3857.Projection_('EPSG:900913'),
5521 new ol.proj.EPSG3857.Projection_('urn:ogc:def:crs:EPSG:6.18:3:3857'),
5522 new ol.proj.EPSG3857.Projection_('urn:ogc:def:crs:EPSG::3857'),
5523 new ol.proj.EPSG3857.Projection_('http://www.opengis.net/gml/srs/epsg.xml#3857')
5524];
5525
5526
5527/**
5528 * Transformation from EPSG:4326 to EPSG:3857.
5529 *
5530 * @param {Array.<number>} input Input array of coordinate values.
5531 * @param {Array.<number>=} opt_output Output array of coordinate values.
5532 * @param {number=} opt_dimension Dimension (default is `2`).
5533 * @return {Array.<number>} Output array of coordinate values.
5534 */
5535ol.proj.EPSG3857.fromEPSG4326 = function(input, opt_output, opt_dimension) {
5536 var length = input.length,
5537 dimension = opt_dimension > 1 ? opt_dimension : 2,
5538 output = opt_output;
5539 if (output === undefined) {
5540 if (dimension > 2) {
5541 // preserve values beyond second dimension
5542 output = input.slice();
5543 } else {
5544 output = new Array(length);
5545 }
5546 }
5547 var halfSize = ol.proj.EPSG3857.HALF_SIZE;
5548 for (var i = 0; i < length; i += dimension) {
5549 output[i] = halfSize * input[i] / 180;
5550 var y = ol.proj.EPSG3857.RADIUS *
5551 Math.log(Math.tan(Math.PI * (input[i + 1] + 90) / 360));
5552 if (y > halfSize) {
5553 y = halfSize;
5554 } else if (y < -halfSize) {
5555 y = -halfSize;
5556 }
5557 output[i + 1] = y;
5558 }
5559 return output;
5560};
5561
5562
5563/**
5564 * Transformation from EPSG:3857 to EPSG:4326.
5565 *
5566 * @param {Array.<number>} input Input array of coordinate values.
5567 * @param {Array.<number>=} opt_output Output array of coordinate values.
5568 * @param {number=} opt_dimension Dimension (default is `2`).
5569 * @return {Array.<number>} Output array of coordinate values.
5570 */
5571ol.proj.EPSG3857.toEPSG4326 = function(input, opt_output, opt_dimension) {
5572 var length = input.length,
5573 dimension = opt_dimension > 1 ? opt_dimension : 2,
5574 output = opt_output;
5575 if (output === undefined) {
5576 if (dimension > 2) {
5577 // preserve values beyond second dimension
5578 output = input.slice();
5579 } else {
5580 output = new Array(length);
5581 }
5582 }
5583 for (var i = 0; i < length; i += dimension) {
5584 output[i] = 180 * input[i] / ol.proj.EPSG3857.HALF_SIZE;
5585 output[i + 1] = 360 * Math.atan(
5586 Math.exp(input[i + 1] / ol.proj.EPSG3857.RADIUS)) / Math.PI - 90;
5587 }
5588 return output;
5589};
5590
5591goog.provide('ol.proj.EPSG4326');
5592
5593goog.require('ol');
5594goog.require('ol.proj.Projection');
5595goog.require('ol.proj.Units');
5596
5597
5598/**
5599 * @classdesc
5600 * Projection object for WGS84 geographic coordinates (EPSG:4326).
5601 *
5602 * Note that OpenLayers does not strictly comply with the EPSG definition.
5603 * The EPSG registry defines 4326 as a CRS for Latitude,Longitude (y,x).
5604 * OpenLayers treats EPSG:4326 as a pseudo-projection, with x,y coordinates.
5605 *
5606 * @constructor
5607 * @extends {ol.proj.Projection}
5608 * @param {string} code Code.
5609 * @param {string=} opt_axisOrientation Axis orientation.
5610 * @private
5611 */
5612ol.proj.EPSG4326.Projection_ = function(code, opt_axisOrientation) {
5613 ol.proj.Projection.call(this, {
5614 code: code,
5615 units: ol.proj.Units.DEGREES,
5616 extent: ol.proj.EPSG4326.EXTENT,
5617 axisOrientation: opt_axisOrientation,
5618 global: true,
5619 metersPerUnit: ol.proj.EPSG4326.METERS_PER_UNIT,
5620 worldExtent: ol.proj.EPSG4326.EXTENT
5621 });
5622};
5623ol.inherits(ol.proj.EPSG4326.Projection_, ol.proj.Projection);
5624
5625
5626/**
5627 * Radius of WGS84 sphere
5628 *
5629 * @const
5630 * @type {number}
5631 */
5632ol.proj.EPSG4326.RADIUS = 6378137;
5633
5634
5635/**
5636 * Extent of the EPSG:4326 projection which is the whole world.
5637 *
5638 * @const
5639 * @type {ol.Extent}
5640 */
5641ol.proj.EPSG4326.EXTENT = [-180, -90, 180, 90];
5642
5643
5644/**
5645 * @const
5646 * @type {number}
5647 */
5648ol.proj.EPSG4326.METERS_PER_UNIT = Math.PI * ol.proj.EPSG4326.RADIUS / 180;
5649
5650
5651/**
5652 * Projections equal to EPSG:4326.
5653 *
5654 * @const
5655 * @type {Array.<ol.proj.Projection>}
5656 */
5657ol.proj.EPSG4326.PROJECTIONS = [
5658 new ol.proj.EPSG4326.Projection_('CRS:84'),
5659 new ol.proj.EPSG4326.Projection_('EPSG:4326', 'neu'),
5660 new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG::4326', 'neu'),
5661 new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:EPSG:6.6:4326', 'neu'),
5662 new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:1.3:CRS84'),
5663 new ol.proj.EPSG4326.Projection_('urn:ogc:def:crs:OGC:2:84'),
5664 new ol.proj.EPSG4326.Projection_('http://www.opengis.net/gml/srs/epsg.xml#4326', 'neu'),
5665 new ol.proj.EPSG4326.Projection_('urn:x-ogc:def:crs:EPSG:4326', 'neu')
5666];
5667
5668goog.provide('ol.proj.projections');
5669
5670
5671/**
5672 * @private
5673 * @type {Object.<string, ol.proj.Projection>}
5674 */
5675ol.proj.projections.cache_ = {};
5676
5677
5678/**
5679 * Clear the projections cache.
5680 */
5681ol.proj.projections.clear = function() {
5682 ol.proj.projections.cache_ = {};
5683};
5684
5685
5686/**
5687 * Get a cached projection by code.
5688 * @param {string} code The code for the projection.
5689 * @return {ol.proj.Projection} The projection (if cached).
5690 */
5691ol.proj.projections.get = function(code) {
5692 var projections = ol.proj.projections.cache_;
5693 return projections[code] || null;
5694};
5695
5696
5697/**
5698 * Add a projection to the cache.
5699 * @param {string} code The projection code.
5700 * @param {ol.proj.Projection} projection The projection to cache.
5701 */
5702ol.proj.projections.add = function(code, projection) {
5703 var projections = ol.proj.projections.cache_;
5704 projections[code] = projection;
5705};
5706
5707goog.provide('ol.proj.transforms');
5708
5709goog.require('ol.obj');
5710
5711
5712/**
5713 * @private
5714 * @type {Object.<string, Object.<string, ol.TransformFunction>>}
5715 */
5716ol.proj.transforms.cache_ = {};
5717
5718
5719/**
5720 * Clear the transform cache.
5721 */
5722ol.proj.transforms.clear = function() {
5723 ol.proj.transforms.cache_ = {};
5724};
5725
5726
5727/**
5728 * Registers a conversion function to convert coordinates from the source
5729 * projection to the destination projection.
5730 *
5731 * @param {ol.proj.Projection} source Source.
5732 * @param {ol.proj.Projection} destination Destination.
5733 * @param {ol.TransformFunction} transformFn Transform.
5734 */
5735ol.proj.transforms.add = function(source, destination, transformFn) {
5736 var sourceCode = source.getCode();
5737 var destinationCode = destination.getCode();
5738 var transforms = ol.proj.transforms.cache_;
5739 if (!(sourceCode in transforms)) {
5740 transforms[sourceCode] = {};
5741 }
5742 transforms[sourceCode][destinationCode] = transformFn;
5743};
5744
5745
5746/**
5747 * Unregisters the conversion function to convert coordinates from the source
5748 * projection to the destination projection. This method is used to clean up
5749 * cached transforms during testing.
5750 *
5751 * @param {ol.proj.Projection} source Source projection.
5752 * @param {ol.proj.Projection} destination Destination projection.
5753 * @return {ol.TransformFunction} transformFn The unregistered transform.
5754 */
5755ol.proj.transforms.remove = function(source, destination) {
5756 var sourceCode = source.getCode();
5757 var destinationCode = destination.getCode();
5758 var transforms = ol.proj.transforms.cache_;
5759 var transform = transforms[sourceCode][destinationCode];
5760 delete transforms[sourceCode][destinationCode];
5761 if (ol.obj.isEmpty(transforms[sourceCode])) {
5762 delete transforms[sourceCode];
5763 }
5764 return transform;
5765};
5766
5767
5768/**
5769 * Get a transform given a source code and a destination code.
5770 * @param {string} sourceCode The code for the source projection.
5771 * @param {string} destinationCode The code for the destination projection.
5772 * @return {ol.TransformFunction|undefined} The transform function (if found).
5773 */
5774ol.proj.transforms.get = function(sourceCode, destinationCode) {
5775 var transform;
5776 var transforms = ol.proj.transforms.cache_;
5777 if (sourceCode in transforms && destinationCode in transforms[sourceCode]) {
5778 transform = transforms[sourceCode][destinationCode];
5779 }
5780 return transform;
5781};
5782
5783goog.provide('ol.proj');
5784
5785goog.require('ol');
5786goog.require('ol.Sphere');
5787goog.require('ol.extent');
5788goog.require('ol.proj.EPSG3857');
5789goog.require('ol.proj.EPSG4326');
5790goog.require('ol.proj.Projection');
5791goog.require('ol.proj.Units');
5792goog.require('ol.proj.proj4');
5793goog.require('ol.proj.projections');
5794goog.require('ol.proj.transforms');
5795
5796
5797/**
5798 * Meters per unit lookup table.
5799 * @const
5800 * @type {Object.<ol.proj.Units, number>}
5801 * @api
5802 */
5803ol.proj.METERS_PER_UNIT = ol.proj.Units.METERS_PER_UNIT;
5804
5805
5806/**
5807 * A place to store the mean radius of the Earth.
5808 * @private
5809 * @type {ol.Sphere}
5810 */
5811ol.proj.SPHERE_ = new ol.Sphere(ol.Sphere.DEFAULT_RADIUS);
5812
5813
5814if (ol.ENABLE_PROJ4JS) {
5815 /**
5816 * Register proj4. If not explicitly registered, it will be assumed that
5817 * proj4js will be loaded in the global namespace. For example in a
5818 * browserify ES6 environment you could use:
5819 *
5820 * import ol from 'openlayers';
5821 * import proj4 from 'proj4';
5822 * ol.proj.setProj4(proj4);
5823 *
5824 * @param {Proj4} proj4 Proj4.
5825 * @api
5826 */
5827 ol.proj.setProj4 = function(proj4) {
5828 ol.proj.proj4.set(proj4);
5829 };
5830}
5831
5832
5833/**
5834 * Get the resolution of the point in degrees or distance units.
5835 * For projections with degrees as the unit this will simply return the
5836 * provided resolution. For other projections the point resolution is
5837 * by default estimated by transforming the 'point' pixel to EPSG:4326,
5838 * measuring its width and height on the normal sphere,
5839 * and taking the average of the width and height.
5840 * A custom function can be provided for a specific projection, either
5841 * by setting the `getPointResolution` option in the
5842 * {@link ol.proj.Projection} constructor or by using
5843 * {@link ol.proj.Projection#setGetPointResolution} to change an existing
5844 * projection object.
5845 * @param {ol.ProjectionLike} projection The projection.
5846 * @param {number} resolution Nominal resolution in projection units.
5847 * @param {ol.Coordinate} point Point to find adjusted resolution at.
5848 * @param {ol.proj.Units=} opt_units Units to get the point resolution in.
5849 * Default is the projection's units.
5850 * @return {number} Point resolution.
5851 * @api
5852 */
5853ol.proj.getPointResolution = function(projection, resolution, point, opt_units) {
5854 projection = ol.proj.get(projection);
5855 var pointResolution;
5856 var getter = projection.getPointResolutionFunc();
5857 if (getter) {
5858 pointResolution = getter(resolution, point);
5859 } else {
5860 var units = projection.getUnits();
5861 if (units == ol.proj.Units.DEGREES && !opt_units || opt_units == ol.proj.Units.DEGREES) {
5862 pointResolution = resolution;
5863 } else {
5864 // Estimate point resolution by transforming the center pixel to EPSG:4326,
5865 // measuring its width and height on the normal sphere, and taking the
5866 // average of the width and height.
5867 var toEPSG4326 = ol.proj.getTransformFromProjections(projection, ol.proj.get('EPSG:4326'));
5868 var vertices = [
5869 point[0] - resolution / 2, point[1],
5870 point[0] + resolution / 2, point[1],
5871 point[0], point[1] - resolution / 2,
5872 point[0], point[1] + resolution / 2
5873 ];
5874 vertices = toEPSG4326(vertices, vertices, 2);
5875 var width = ol.proj.SPHERE_.haversineDistance(
5876 vertices.slice(0, 2), vertices.slice(2, 4));
5877 var height = ol.proj.SPHERE_.haversineDistance(
5878 vertices.slice(4, 6), vertices.slice(6, 8));
5879 pointResolution = (width + height) / 2;
5880 var metersPerUnit = opt_units ?
5881 ol.proj.Units.METERS_PER_UNIT[opt_units] :
5882 projection.getMetersPerUnit();
5883 if (metersPerUnit !== undefined) {
5884 pointResolution /= metersPerUnit;
5885 }
5886 }
5887 }
5888 return pointResolution;
5889};
5890
5891
5892/**
5893 * Registers transformation functions that don't alter coordinates. Those allow
5894 * to transform between projections with equal meaning.
5895 *
5896 * @param {Array.<ol.proj.Projection>} projections Projections.
5897 * @api
5898 */
5899ol.proj.addEquivalentProjections = function(projections) {
5900 ol.proj.addProjections(projections);
5901 projections.forEach(function(source) {
5902 projections.forEach(function(destination) {
5903 if (source !== destination) {
5904 ol.proj.transforms.add(source, destination, ol.proj.cloneTransform);
5905 }
5906 });
5907 });
5908};
5909
5910
5911/**
5912 * Registers transformation functions to convert coordinates in any projection
5913 * in projection1 to any projection in projection2.
5914 *
5915 * @param {Array.<ol.proj.Projection>} projections1 Projections with equal
5916 * meaning.
5917 * @param {Array.<ol.proj.Projection>} projections2 Projections with equal
5918 * meaning.
5919 * @param {ol.TransformFunction} forwardTransform Transformation from any
5920 * projection in projection1 to any projection in projection2.
5921 * @param {ol.TransformFunction} inverseTransform Transform from any projection
5922 * in projection2 to any projection in projection1..
5923 */
5924ol.proj.addEquivalentTransforms = function(projections1, projections2, forwardTransform, inverseTransform) {
5925 projections1.forEach(function(projection1) {
5926 projections2.forEach(function(projection2) {
5927 ol.proj.transforms.add(projection1, projection2, forwardTransform);
5928 ol.proj.transforms.add(projection2, projection1, inverseTransform);
5929 });
5930 });
5931};
5932
5933
5934/**
5935 * Add a Projection object to the list of supported projections that can be
5936 * looked up by their code.
5937 *
5938 * @param {ol.proj.Projection} projection Projection instance.
5939 * @api
5940 */
5941ol.proj.addProjection = function(projection) {
5942 ol.proj.projections.add(projection.getCode(), projection);
5943 ol.proj.transforms.add(projection, projection, ol.proj.cloneTransform);
5944};
5945
5946
5947/**
5948 * @param {Array.<ol.proj.Projection>} projections Projections.
5949 */
5950ol.proj.addProjections = function(projections) {
5951 projections.forEach(ol.proj.addProjection);
5952};
5953
5954
5955/**
5956 * Clear all cached projections and transforms.
5957 */
5958ol.proj.clearAllProjections = function() {
5959 ol.proj.projections.clear();
5960 ol.proj.transforms.clear();
5961};
5962
5963
5964/**
5965 * @param {ol.proj.Projection|string|undefined} projection Projection.
5966 * @param {string} defaultCode Default code.
5967 * @return {ol.proj.Projection} Projection.
5968 */
5969ol.proj.createProjection = function(projection, defaultCode) {
5970 if (!projection) {
5971 return ol.proj.get(defaultCode);
5972 } else if (typeof projection === 'string') {
5973 return ol.proj.get(projection);
5974 } else {
5975 return /** @type {ol.proj.Projection} */ (projection);
5976 }
5977};
5978
5979
5980/**
5981 * Registers coordinate transform functions to convert coordinates between the
5982 * source projection and the destination projection.
5983 * The forward and inverse functions convert coordinate pairs; this function
5984 * converts these into the functions used internally which also handle
5985 * extents and coordinate arrays.
5986 *
5987 * @param {ol.ProjectionLike} source Source projection.
5988 * @param {ol.ProjectionLike} destination Destination projection.
5989 * @param {function(ol.Coordinate): ol.Coordinate} forward The forward transform
5990 * function (that is, from the source projection to the destination
5991 * projection) that takes a {@link ol.Coordinate} as argument and returns
5992 * the transformed {@link ol.Coordinate}.
5993 * @param {function(ol.Coordinate): ol.Coordinate} inverse The inverse transform
5994 * function (that is, from the destination projection to the source
5995 * projection) that takes a {@link ol.Coordinate} as argument and returns
5996 * the transformed {@link ol.Coordinate}.
5997 * @api
5998 */
5999ol.proj.addCoordinateTransforms = function(source, destination, forward, inverse) {
6000 var sourceProj = ol.proj.get(source);
6001 var destProj = ol.proj.get(destination);
6002 ol.proj.transforms.add(sourceProj, destProj,
6003 ol.proj.createTransformFromCoordinateTransform(forward));
6004 ol.proj.transforms.add(destProj, sourceProj,
6005 ol.proj.createTransformFromCoordinateTransform(inverse));
6006};
6007
6008
6009/**
6010 * Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform
6011 * function.
6012 * @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate
6013 * transform.
6014 * @return {ol.TransformFunction} Transform function.
6015 */
6016ol.proj.createTransformFromCoordinateTransform = function(transform) {
6017 return (
6018 /**
6019 * @param {Array.<number>} input Input.
6020 * @param {Array.<number>=} opt_output Output.
6021 * @param {number=} opt_dimension Dimension.
6022 * @return {Array.<number>} Output.
6023 */
6024 function(input, opt_output, opt_dimension) {
6025 var length = input.length;
6026 var dimension = opt_dimension !== undefined ? opt_dimension : 2;
6027 var output = opt_output !== undefined ? opt_output : new Array(length);
6028 var point, i, j;
6029 for (i = 0; i < length; i += dimension) {
6030 point = transform([input[i], input[i + 1]]);
6031 output[i] = point[0];
6032 output[i + 1] = point[1];
6033 for (j = dimension - 1; j >= 2; --j) {
6034 output[i + j] = input[i + j];
6035 }
6036 }
6037 return output;
6038 });
6039};
6040
6041
6042/**
6043 * Transforms a coordinate from longitude/latitude to a different projection.
6044 * @param {ol.Coordinate} coordinate Coordinate as longitude and latitude, i.e.
6045 * an array with longitude as 1st and latitude as 2nd element.
6046 * @param {ol.ProjectionLike=} opt_projection Target projection. The
6047 * default is Web Mercator, i.e. 'EPSG:3857'.
6048 * @return {ol.Coordinate} Coordinate projected to the target projection.
6049 * @api
6050 */
6051ol.proj.fromLonLat = function(coordinate, opt_projection) {
6052 return ol.proj.transform(coordinate, 'EPSG:4326',
6053 opt_projection !== undefined ? opt_projection : 'EPSG:3857');
6054};
6055
6056
6057/**
6058 * Transforms a coordinate to longitude/latitude.
6059 * @param {ol.Coordinate} coordinate Projected coordinate.
6060 * @param {ol.ProjectionLike=} opt_projection Projection of the coordinate.
6061 * The default is Web Mercator, i.e. 'EPSG:3857'.
6062 * @return {ol.Coordinate} Coordinate as longitude and latitude, i.e. an array
6063 * with longitude as 1st and latitude as 2nd element.
6064 * @api
6065 */
6066ol.proj.toLonLat = function(coordinate, opt_projection) {
6067 return ol.proj.transform(coordinate,
6068 opt_projection !== undefined ? opt_projection : 'EPSG:3857', 'EPSG:4326');
6069};
6070
6071
6072/**
6073 * Fetches a Projection object for the code specified.
6074 *
6075 * @param {ol.ProjectionLike} projectionLike Either a code string which is
6076 * a combination of authority and identifier such as "EPSG:4326", or an
6077 * existing projection object, or undefined.
6078 * @return {ol.proj.Projection} Projection object, or null if not in list.
6079 * @api
6080 */
6081ol.proj.get = function(projectionLike) {
6082 var projection = null;
6083 if (projectionLike instanceof ol.proj.Projection) {
6084 projection = projectionLike;
6085 } else if (typeof projectionLike === 'string') {
6086 var code = projectionLike;
6087 projection = ol.proj.projections.get(code);
6088 if (ol.ENABLE_PROJ4JS && !projection) {
6089 var proj4js = ol.proj.proj4.get();
6090 if (typeof proj4js == 'function' &&
6091 proj4js.defs(code) !== undefined) {
6092 projection = new ol.proj.Projection({code: code});
6093 ol.proj.addProjection(projection);
6094 }
6095 }
6096 }
6097 return projection;
6098};
6099
6100
6101/**
6102 * Checks if two projections are the same, that is every coordinate in one
6103 * projection does represent the same geographic point as the same coordinate in
6104 * the other projection.
6105 *
6106 * @param {ol.proj.Projection} projection1 Projection 1.
6107 * @param {ol.proj.Projection} projection2 Projection 2.
6108 * @return {boolean} Equivalent.
6109 * @api
6110 */
6111ol.proj.equivalent = function(projection1, projection2) {
6112 if (projection1 === projection2) {
6113 return true;
6114 }
6115 var equalUnits = projection1.getUnits() === projection2.getUnits();
6116 if (projection1.getCode() === projection2.getCode()) {
6117 return equalUnits;
6118 } else {
6119 var transformFn = ol.proj.getTransformFromProjections(
6120 projection1, projection2);
6121 return transformFn === ol.proj.cloneTransform && equalUnits;
6122 }
6123};
6124
6125
6126/**
6127 * Given the projection-like objects, searches for a transformation
6128 * function to convert a coordinates array from the source projection to the
6129 * destination projection.
6130 *
6131 * @param {ol.ProjectionLike} source Source.
6132 * @param {ol.ProjectionLike} destination Destination.
6133 * @return {ol.TransformFunction} Transform function.
6134 * @api
6135 */
6136ol.proj.getTransform = function(source, destination) {
6137 var sourceProjection = ol.proj.get(source);
6138 var destinationProjection = ol.proj.get(destination);
6139 return ol.proj.getTransformFromProjections(
6140 sourceProjection, destinationProjection);
6141};
6142
6143
6144/**
6145 * Searches in the list of transform functions for the function for converting
6146 * coordinates from the source projection to the destination projection.
6147 *
6148 * @param {ol.proj.Projection} sourceProjection Source Projection object.
6149 * @param {ol.proj.Projection} destinationProjection Destination Projection
6150 * object.
6151 * @return {ol.TransformFunction} Transform function.
6152 */
6153ol.proj.getTransformFromProjections = function(sourceProjection, destinationProjection) {
6154 var sourceCode = sourceProjection.getCode();
6155 var destinationCode = destinationProjection.getCode();
6156 var transform = ol.proj.transforms.get(sourceCode, destinationCode);
6157 if (ol.ENABLE_PROJ4JS && !transform) {
6158 var proj4js = ol.proj.proj4.get();
6159 if (typeof proj4js == 'function') {
6160 var sourceDef = proj4js.defs(sourceCode);
6161 var destinationDef = proj4js.defs(destinationCode);
6162
6163 if (sourceDef !== undefined && destinationDef !== undefined) {
6164 if (sourceDef === destinationDef) {
6165 ol.proj.addEquivalentProjections([destinationProjection, sourceProjection]);
6166 } else {
6167 var proj4Transform = proj4js(destinationCode, sourceCode);
6168 ol.proj.addCoordinateTransforms(destinationProjection, sourceProjection,
6169 proj4Transform.forward, proj4Transform.inverse);
6170 }
6171 transform = ol.proj.transforms.get(sourceCode, destinationCode);
6172 }
6173 }
6174 }
6175 if (!transform) {
6176 transform = ol.proj.identityTransform;
6177 }
6178 return transform;
6179};
6180
6181
6182/**
6183 * @param {Array.<number>} input Input coordinate array.
6184 * @param {Array.<number>=} opt_output Output array of coordinate values.
6185 * @param {number=} opt_dimension Dimension.
6186 * @return {Array.<number>} Input coordinate array (same array as input).
6187 */
6188ol.proj.identityTransform = function(input, opt_output, opt_dimension) {
6189 if (opt_output !== undefined && input !== opt_output) {
6190 for (var i = 0, ii = input.length; i < ii; ++i) {
6191 opt_output[i] = input[i];
6192 }
6193 input = opt_output;
6194 }
6195 return input;
6196};
6197
6198
6199/**
6200 * @param {Array.<number>} input Input coordinate array.
6201 * @param {Array.<number>=} opt_output Output array of coordinate values.
6202 * @param {number=} opt_dimension Dimension.
6203 * @return {Array.<number>} Output coordinate array (new array, same coordinate
6204 * values).
6205 */
6206ol.proj.cloneTransform = function(input, opt_output, opt_dimension) {
6207 var output;
6208 if (opt_output !== undefined) {
6209 for (var i = 0, ii = input.length; i < ii; ++i) {
6210 opt_output[i] = input[i];
6211 }
6212 output = opt_output;
6213 } else {
6214 output = input.slice();
6215 }
6216 return output;
6217};
6218
6219
6220/**
6221 * Transforms a coordinate from source projection to destination projection.
6222 * This returns a new coordinate (and does not modify the original).
6223 *
6224 * See {@link ol.proj.transformExtent} for extent transformation.
6225 * See the transform method of {@link ol.geom.Geometry} and its subclasses for
6226 * geometry transforms.
6227 *
6228 * @param {ol.Coordinate} coordinate Coordinate.
6229 * @param {ol.ProjectionLike} source Source projection-like.
6230 * @param {ol.ProjectionLike} destination Destination projection-like.
6231 * @return {ol.Coordinate} Coordinate.
6232 * @api
6233 */
6234ol.proj.transform = function(coordinate, source, destination) {
6235 var transformFn = ol.proj.getTransform(source, destination);
6236 return transformFn(coordinate, undefined, coordinate.length);
6237};
6238
6239
6240/**
6241 * Transforms an extent from source projection to destination projection. This
6242 * returns a new extent (and does not modify the original).
6243 *
6244 * @param {ol.Extent} extent The extent to transform.
6245 * @param {ol.ProjectionLike} source Source projection-like.
6246 * @param {ol.ProjectionLike} destination Destination projection-like.
6247 * @return {ol.Extent} The transformed extent.
6248 * @api
6249 */
6250ol.proj.transformExtent = function(extent, source, destination) {
6251 var transformFn = ol.proj.getTransform(source, destination);
6252 return ol.extent.applyTransform(extent, transformFn);
6253};
6254
6255
6256/**
6257 * Transforms the given point to the destination projection.
6258 *
6259 * @param {ol.Coordinate} point Point.
6260 * @param {ol.proj.Projection} sourceProjection Source projection.
6261 * @param {ol.proj.Projection} destinationProjection Destination projection.
6262 * @return {ol.Coordinate} Point.
6263 */
6264ol.proj.transformWithProjections = function(point, sourceProjection, destinationProjection) {
6265 var transformFn = ol.proj.getTransformFromProjections(
6266 sourceProjection, destinationProjection);
6267 return transformFn(point);
6268};
6269
6270/**
6271 * Add transforms to and from EPSG:4326 and EPSG:3857. This function is called
6272 * by when this module is executed and should only need to be called again after
6273 * `ol.proj.clearAllProjections()` is called (e.g. in tests).
6274 */
6275ol.proj.addCommon = function() {
6276 // Add transformations that don't alter coordinates to convert within set of
6277 // projections with equal meaning.
6278 ol.proj.addEquivalentProjections(ol.proj.EPSG3857.PROJECTIONS);
6279 ol.proj.addEquivalentProjections(ol.proj.EPSG4326.PROJECTIONS);
6280 // Add transformations to convert EPSG:4326 like coordinates to EPSG:3857 like
6281 // coordinates and back.
6282 ol.proj.addEquivalentTransforms(
6283 ol.proj.EPSG4326.PROJECTIONS,
6284 ol.proj.EPSG3857.PROJECTIONS,
6285 ol.proj.EPSG3857.fromEPSG4326,
6286 ol.proj.EPSG3857.toEPSG4326);
6287};
6288
6289ol.proj.addCommon();
6290
6291goog.provide('ol.tilecoord');
6292
6293
6294/**
6295 * @param {number} z Z.
6296 * @param {number} x X.
6297 * @param {number} y Y.
6298 * @param {ol.TileCoord=} opt_tileCoord Tile coordinate.
6299 * @return {ol.TileCoord} Tile coordinate.
6300 */
6301ol.tilecoord.createOrUpdate = function(z, x, y, opt_tileCoord) {
6302 if (opt_tileCoord !== undefined) {
6303 opt_tileCoord[0] = z;
6304 opt_tileCoord[1] = x;
6305 opt_tileCoord[2] = y;
6306 return opt_tileCoord;
6307 } else {
6308 return [z, x, y];
6309 }
6310};
6311
6312
6313/**
6314 * @param {number} z Z.
6315 * @param {number} x X.
6316 * @param {number} y Y.
6317 * @return {string} Key.
6318 */
6319ol.tilecoord.getKeyZXY = function(z, x, y) {
6320 return z + '/' + x + '/' + y;
6321};
6322
6323
6324/**
6325 * @param {ol.TileCoord} tileCoord Tile coord.
6326 * @return {number} Hash.
6327 */
6328ol.tilecoord.hash = function(tileCoord) {
6329 return (tileCoord[1] << tileCoord[0]) + tileCoord[2];
6330};
6331
6332
6333/**
6334 * @param {ol.TileCoord} tileCoord Tile coord.
6335 * @return {string} Quad key.
6336 */
6337ol.tilecoord.quadKey = function(tileCoord) {
6338 var z = tileCoord[0];
6339 var digits = new Array(z);
6340 var mask = 1 << (z - 1);
6341 var i, charCode;
6342 for (i = 0; i < z; ++i) {
6343 // 48 is charCode for 0 - '0'.charCodeAt(0)
6344 charCode = 48;
6345 if (tileCoord[1] & mask) {
6346 charCode += 1;
6347 }
6348 if (tileCoord[2] & mask) {
6349 charCode += 2;
6350 }
6351 digits[i] = String.fromCharCode(charCode);
6352 mask >>= 1;
6353 }
6354 return digits.join('');
6355};
6356
6357
6358/**
6359 * @param {ol.TileCoord} tileCoord Tile coordinate.
6360 * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.
6361 * @return {boolean} Tile coordinate is within extent and zoom level range.
6362 */
6363ol.tilecoord.withinExtentAndZ = function(tileCoord, tileGrid) {
6364 var z = tileCoord[0];
6365 var x = tileCoord[1];
6366 var y = tileCoord[2];
6367
6368 if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) {
6369 return false;
6370 }
6371 var extent = tileGrid.getExtent();
6372 var tileRange;
6373 if (!extent) {
6374 tileRange = tileGrid.getFullTileRange(z);
6375 } else {
6376 tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
6377 }
6378 if (!tileRange) {
6379 return true;
6380 } else {
6381 return tileRange.containsXY(x, y);
6382 }
6383};
6384
6385goog.provide('ol.tilegrid.TileGrid');
6386
6387goog.require('ol');
6388goog.require('ol.asserts');
6389goog.require('ol.TileRange');
6390goog.require('ol.array');
6391goog.require('ol.extent');
6392goog.require('ol.math');
6393goog.require('ol.size');
6394goog.require('ol.tilecoord');
6395
6396
6397/**
6398 * @classdesc
6399 * Base class for setting the grid pattern for sources accessing tiled-image
6400 * servers.
6401 *
6402 * @constructor
6403 * @param {olx.tilegrid.TileGridOptions} options Tile grid options.
6404 * @struct
6405 * @api
6406 */
6407ol.tilegrid.TileGrid = function(options) {
6408
6409 /**
6410 * @protected
6411 * @type {number}
6412 */
6413 this.minZoom = options.minZoom !== undefined ? options.minZoom : 0;
6414
6415 /**
6416 * @private
6417 * @type {!Array.<number>}
6418 */
6419 this.resolutions_ = options.resolutions;
6420 ol.asserts.assert(ol.array.isSorted(this.resolutions_, function(a, b) {
6421 return b - a;
6422 }, true), 17); // `resolutions` must be sorted in descending order
6423
6424 /**
6425 * @protected
6426 * @type {number}
6427 */
6428 this.maxZoom = this.resolutions_.length - 1;
6429
6430 /**
6431 * @private
6432 * @type {ol.Coordinate}
6433 */
6434 this.origin_ = options.origin !== undefined ? options.origin : null;
6435
6436 /**
6437 * @private
6438 * @type {Array.<ol.Coordinate>}
6439 */
6440 this.origins_ = null;
6441 if (options.origins !== undefined) {
6442 this.origins_ = options.origins;
6443 ol.asserts.assert(this.origins_.length == this.resolutions_.length,
6444 20); // Number of `origins` and `resolutions` must be equal
6445 }
6446
6447 var extent = options.extent;
6448
6449 if (extent !== undefined &&
6450 !this.origin_ && !this.origins_) {
6451 this.origin_ = ol.extent.getTopLeft(extent);
6452 }
6453
6454 ol.asserts.assert(
6455 (!this.origin_ && this.origins_) || (this.origin_ && !this.origins_),
6456 18); // Either `origin` or `origins` must be configured, never both
6457
6458 /**
6459 * @private
6460 * @type {Array.<number|ol.Size>}
6461 */
6462 this.tileSizes_ = null;
6463 if (options.tileSizes !== undefined) {
6464 this.tileSizes_ = options.tileSizes;
6465 ol.asserts.assert(this.tileSizes_.length == this.resolutions_.length,
6466 19); // Number of `tileSizes` and `resolutions` must be equal
6467 }
6468
6469 /**
6470 * @private
6471 * @type {number|ol.Size}
6472 */
6473 this.tileSize_ = options.tileSize !== undefined ?
6474 options.tileSize :
6475 !this.tileSizes_ ? ol.DEFAULT_TILE_SIZE : null;
6476 ol.asserts.assert(
6477 (!this.tileSize_ && this.tileSizes_) ||
6478 (this.tileSize_ && !this.tileSizes_),
6479 22); // Either `tileSize` or `tileSizes` must be configured, never both
6480
6481 /**
6482 * @private
6483 * @type {ol.Extent}
6484 */
6485 this.extent_ = extent !== undefined ? extent : null;
6486
6487
6488 /**
6489 * @private
6490 * @type {Array.<ol.TileRange>}
6491 */
6492 this.fullTileRanges_ = null;
6493
6494 /**
6495 * @private
6496 * @type {ol.Size}
6497 */
6498 this.tmpSize_ = [0, 0];
6499
6500 if (options.sizes !== undefined) {
6501 this.fullTileRanges_ = options.sizes.map(function(size, z) {
6502 var tileRange = new ol.TileRange(
6503 Math.min(0, size[0]), Math.max(size[0] - 1, -1),
6504 Math.min(0, size[1]), Math.max(size[1] - 1, -1));
6505 return tileRange;
6506 }, this);
6507 } else if (extent) {
6508 this.calculateTileRanges_(extent);
6509 }
6510
6511};
6512
6513
6514/**
6515 * @private
6516 * @type {ol.TileCoord}
6517 */
6518ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0];
6519
6520
6521/**
6522 * Call a function with each tile coordinate for a given extent and zoom level.
6523 *
6524 * @param {ol.Extent} extent Extent.
6525 * @param {number} zoom Zoom level.
6526 * @param {function(ol.TileCoord)} callback Function called with each tile coordinate.
6527 * @api
6528 */
6529ol.tilegrid.TileGrid.prototype.forEachTileCoord = function(extent, zoom, callback) {
6530 var tileRange = this.getTileRangeForExtentAndZ(extent, zoom);
6531 for (var i = tileRange.minX, ii = tileRange.maxX; i <= ii; ++i) {
6532 for (var j = tileRange.minY, jj = tileRange.maxY; j <= jj; ++j) {
6533 callback([zoom, i, j]);
6534 }
6535 }
6536};
6537
6538
6539/**
6540 * @param {ol.TileCoord} tileCoord Tile coordinate.
6541 * @param {function(this: T, number, ol.TileRange): boolean} callback Callback.
6542 * @param {T=} opt_this The object to use as `this` in `callback`.
6543 * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.
6544 * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
6545 * @return {boolean} Callback succeeded.
6546 * @template T
6547 */
6548ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange = function(tileCoord, callback, opt_this, opt_tileRange, opt_extent) {
6549 var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);
6550 var z = tileCoord[0] - 1;
6551 while (z >= this.minZoom) {
6552 if (callback.call(opt_this, z,
6553 this.getTileRangeForExtentAndZ(tileCoordExtent, z, opt_tileRange))) {
6554 return true;
6555 }
6556 --z;
6557 }
6558 return false;
6559};
6560
6561
6562/**
6563 * Get the extent for this tile grid, if it was configured.
6564 * @return {ol.Extent} Extent.
6565 */
6566ol.tilegrid.TileGrid.prototype.getExtent = function() {
6567 return this.extent_;
6568};
6569
6570
6571/**
6572 * Get the maximum zoom level for the grid.
6573 * @return {number} Max zoom.
6574 * @api
6575 */
6576ol.tilegrid.TileGrid.prototype.getMaxZoom = function() {
6577 return this.maxZoom;
6578};
6579
6580
6581/**
6582 * Get the minimum zoom level for the grid.
6583 * @return {number} Min zoom.
6584 * @api
6585 */
6586ol.tilegrid.TileGrid.prototype.getMinZoom = function() {
6587 return this.minZoom;
6588};
6589
6590
6591/**
6592 * Get the origin for the grid at the given zoom level.
6593 * @param {number} z Z.
6594 * @return {ol.Coordinate} Origin.
6595 * @api
6596 */
6597ol.tilegrid.TileGrid.prototype.getOrigin = function(z) {
6598 if (this.origin_) {
6599 return this.origin_;
6600 } else {
6601 return this.origins_[z];
6602 }
6603};
6604
6605
6606/**
6607 * Get the resolution for the given zoom level.
6608 * @param {number} z Z.
6609 * @return {number} Resolution.
6610 * @api
6611 */
6612ol.tilegrid.TileGrid.prototype.getResolution = function(z) {
6613 return this.resolutions_[z];
6614};
6615
6616
6617/**
6618 * Get the list of resolutions for the tile grid.
6619 * @return {Array.<number>} Resolutions.
6620 * @api
6621 */
6622ol.tilegrid.TileGrid.prototype.getResolutions = function() {
6623 return this.resolutions_;
6624};
6625
6626
6627/**
6628 * @param {ol.TileCoord} tileCoord Tile coordinate.
6629 * @param {ol.TileRange=} opt_tileRange Temporary ol.TileRange object.
6630 * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
6631 * @return {ol.TileRange} Tile range.
6632 */
6633ol.tilegrid.TileGrid.prototype.getTileCoordChildTileRange = function(tileCoord, opt_tileRange, opt_extent) {
6634 if (tileCoord[0] < this.maxZoom) {
6635 var tileCoordExtent = this.getTileCoordExtent(tileCoord, opt_extent);
6636 return this.getTileRangeForExtentAndZ(
6637 tileCoordExtent, tileCoord[0] + 1, opt_tileRange);
6638 } else {
6639 return null;
6640 }
6641};
6642
6643
6644/**
6645 * @param {number} z Z.
6646 * @param {ol.TileRange} tileRange Tile range.
6647 * @param {ol.Extent=} opt_extent Temporary ol.Extent object.
6648 * @return {ol.Extent} Extent.
6649 */
6650ol.tilegrid.TileGrid.prototype.getTileRangeExtent = function(z, tileRange, opt_extent) {
6651 var origin = this.getOrigin(z);
6652 var resolution = this.getResolution(z);
6653 var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
6654 var minX = origin[0] + tileRange.minX * tileSize[0] * resolution;
6655 var maxX = origin[0] + (tileRange.maxX + 1) * tileSize[0] * resolution;
6656 var minY = origin[1] + tileRange.minY * tileSize[1] * resolution;
6657 var maxY = origin[1] + (tileRange.maxY + 1) * tileSize[1] * resolution;
6658 return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
6659};
6660
6661
6662/**
6663 * @param {ol.Extent} extent Extent.
6664 * @param {number} resolution Resolution.
6665 * @param {ol.TileRange=} opt_tileRange Temporary tile range object.
6666 * @return {ol.TileRange} Tile range.
6667 */
6668ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndResolution = function(extent, resolution, opt_tileRange) {
6669 var tileCoord = ol.tilegrid.TileGrid.tmpTileCoord_;
6670 this.getTileCoordForXYAndResolution_(
6671 extent[0], extent[1], resolution, false, tileCoord);
6672 var minX = tileCoord[1];
6673 var minY = tileCoord[2];
6674 this.getTileCoordForXYAndResolution_(
6675 extent[2], extent[3], resolution, true, tileCoord);
6676 return ol.TileRange.createOrUpdate(
6677 minX, tileCoord[1], minY, tileCoord[2], opt_tileRange);
6678};
6679
6680
6681/**
6682 * @param {ol.Extent} extent Extent.
6683 * @param {number} z Z.
6684 * @param {ol.TileRange=} opt_tileRange Temporary tile range object.
6685 * @return {ol.TileRange} Tile range.
6686 */
6687ol.tilegrid.TileGrid.prototype.getTileRangeForExtentAndZ = function(extent, z, opt_tileRange) {
6688 var resolution = this.getResolution(z);
6689 return this.getTileRangeForExtentAndResolution(
6690 extent, resolution, opt_tileRange);
6691};
6692
6693
6694/**
6695 * @param {ol.TileCoord} tileCoord Tile coordinate.
6696 * @return {ol.Coordinate} Tile center.
6697 */
6698ol.tilegrid.TileGrid.prototype.getTileCoordCenter = function(tileCoord) {
6699 var origin = this.getOrigin(tileCoord[0]);
6700 var resolution = this.getResolution(tileCoord[0]);
6701 var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
6702 return [
6703 origin[0] + (tileCoord[1] + 0.5) * tileSize[0] * resolution,
6704 origin[1] + (tileCoord[2] + 0.5) * tileSize[1] * resolution
6705 ];
6706};
6707
6708
6709/**
6710 * Get the extent of a tile coordinate.
6711 *
6712 * @param {ol.TileCoord} tileCoord Tile coordinate.
6713 * @param {ol.Extent=} opt_extent Temporary extent object.
6714 * @return {ol.Extent} Extent.
6715 * @api
6716 */
6717ol.tilegrid.TileGrid.prototype.getTileCoordExtent = function(tileCoord, opt_extent) {
6718 var origin = this.getOrigin(tileCoord[0]);
6719 var resolution = this.getResolution(tileCoord[0]);
6720 var tileSize = ol.size.toSize(this.getTileSize(tileCoord[0]), this.tmpSize_);
6721 var minX = origin[0] + tileCoord[1] * tileSize[0] * resolution;
6722 var minY = origin[1] + tileCoord[2] * tileSize[1] * resolution;
6723 var maxX = minX + tileSize[0] * resolution;
6724 var maxY = minY + tileSize[1] * resolution;
6725 return ol.extent.createOrUpdate(minX, minY, maxX, maxY, opt_extent);
6726};
6727
6728
6729/**
6730 * Get the tile coordinate for the given map coordinate and resolution. This
6731 * method considers that coordinates that intersect tile boundaries should be
6732 * assigned the higher tile coordinate.
6733 *
6734 * @param {ol.Coordinate} coordinate Coordinate.
6735 * @param {number} resolution Resolution.
6736 * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.
6737 * @return {ol.TileCoord} Tile coordinate.
6738 * @api
6739 */
6740ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution = function(coordinate, resolution, opt_tileCoord) {
6741 return this.getTileCoordForXYAndResolution_(
6742 coordinate[0], coordinate[1], resolution, false, opt_tileCoord);
6743};
6744
6745
6746/**
6747 * @param {number} x X.
6748 * @param {number} y Y.
6749 * @param {number} resolution Resolution.
6750 * @param {boolean} reverseIntersectionPolicy Instead of letting edge
6751 * intersections go to the higher tile coordinate, let edge intersections
6752 * go to the lower tile coordinate.
6753 * @param {ol.TileCoord=} opt_tileCoord Temporary ol.TileCoord object.
6754 * @return {ol.TileCoord} Tile coordinate.
6755 * @private
6756 */
6757ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(
6758 x, y, resolution, reverseIntersectionPolicy, opt_tileCoord) {
6759 var z = this.getZForResolution(resolution);
6760 var scale = resolution / this.getResolution(z);
6761 var origin = this.getOrigin(z);
6762 var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
6763
6764 var adjustX = reverseIntersectionPolicy ? 0.5 : 0;
6765 var adjustY = reverseIntersectionPolicy ? 0 : 0.5;
6766 var xFromOrigin = Math.floor((x - origin[0]) / resolution + adjustX);
6767 var yFromOrigin = Math.floor((y - origin[1]) / resolution + adjustY);
6768 var tileCoordX = scale * xFromOrigin / tileSize[0];
6769 var tileCoordY = scale * yFromOrigin / tileSize[1];
6770
6771 if (reverseIntersectionPolicy) {
6772 tileCoordX = Math.ceil(tileCoordX) - 1;
6773 tileCoordY = Math.ceil(tileCoordY) - 1;
6774 } else {
6775 tileCoordX = Math.floor(tileCoordX);
6776 tileCoordY = Math.floor(tileCoordY);
6777 }
6778
6779 return ol.tilecoord.createOrUpdate(z, tileCoordX, tileCoordY, opt_tileCoord);
6780};
6781
6782
6783/**
6784 * Get a tile coordinate given a map coordinate and zoom level.
6785 * @param {ol.Coordinate} coordinate Coordinate.
6786 * @param {number} z Zoom level.
6787 * @param {ol.TileCoord=} opt_tileCoord Destination ol.TileCoord object.
6788 * @return {ol.TileCoord} Tile coordinate.
6789 * @api
6790 */
6791ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ = function(coordinate, z, opt_tileCoord) {
6792 var resolution = this.getResolution(z);
6793 return this.getTileCoordForXYAndResolution_(
6794 coordinate[0], coordinate[1], resolution, false, opt_tileCoord);
6795};
6796
6797
6798/**
6799 * @param {ol.TileCoord} tileCoord Tile coordinate.
6800 * @return {number} Tile resolution.
6801 */
6802ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) {
6803 return this.resolutions_[tileCoord[0]];
6804};
6805
6806
6807/**
6808 * Get the tile size for a zoom level. The type of the return value matches the
6809 * `tileSize` or `tileSizes` that the tile grid was configured with. To always
6810 * get an `ol.Size`, run the result through `ol.size.toSize()`.
6811 * @param {number} z Z.
6812 * @return {number|ol.Size} Tile size.
6813 * @api
6814 */
6815ol.tilegrid.TileGrid.prototype.getTileSize = function(z) {
6816 if (this.tileSize_) {
6817 return this.tileSize_;
6818 } else {
6819 return this.tileSizes_[z];
6820 }
6821};
6822
6823
6824/**
6825 * @param {number} z Zoom level.
6826 * @return {ol.TileRange} Extent tile range for the specified zoom level.
6827 */
6828ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) {
6829 if (!this.fullTileRanges_) {
6830 return null;
6831 } else {
6832 return this.fullTileRanges_[z];
6833 }
6834};
6835
6836
6837/**
6838 * @param {number} resolution Resolution.
6839 * @param {number=} opt_direction If 0, the nearest resolution will be used.
6840 * If 1, the nearest lower resolution will be used. If -1, the nearest
6841 * higher resolution will be used. Default is 0.
6842 * @return {number} Z.
6843 * @api
6844 */
6845ol.tilegrid.TileGrid.prototype.getZForResolution = function(
6846 resolution, opt_direction) {
6847 var z = ol.array.linearFindNearest(this.resolutions_, resolution,
6848 opt_direction || 0);
6849 return ol.math.clamp(z, this.minZoom, this.maxZoom);
6850};
6851
6852
6853/**
6854 * @param {!ol.Extent} extent Extent for this tile grid.
6855 * @private
6856 */
6857ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) {
6858 var length = this.resolutions_.length;
6859 var fullTileRanges = new Array(length);
6860 for (var z = this.minZoom; z < length; ++z) {
6861 fullTileRanges[z] = this.getTileRangeForExtentAndZ(extent, z);
6862 }
6863 this.fullTileRanges_ = fullTileRanges;
6864};
6865
6866goog.provide('ol.tilegrid');
6867
6868goog.require('ol');
6869goog.require('ol.size');
6870goog.require('ol.extent');
6871goog.require('ol.extent.Corner');
6872goog.require('ol.obj');
6873goog.require('ol.proj');
6874goog.require('ol.proj.Units');
6875goog.require('ol.tilegrid.TileGrid');
6876
6877
6878/**
6879 * @param {ol.proj.Projection} projection Projection.
6880 * @return {!ol.tilegrid.TileGrid} Default tile grid for the passed projection.
6881 */
6882ol.tilegrid.getForProjection = function(projection) {
6883 var tileGrid = projection.getDefaultTileGrid();
6884 if (!tileGrid) {
6885 tileGrid = ol.tilegrid.createForProjection(projection);
6886 projection.setDefaultTileGrid(tileGrid);
6887 }
6888 return tileGrid;
6889};
6890
6891
6892/**
6893 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
6894 * @param {ol.TileCoord} tileCoord Tile coordinate.
6895 * @param {ol.proj.Projection} projection Projection.
6896 * @return {ol.TileCoord} Tile coordinate.
6897 */
6898ol.tilegrid.wrapX = function(tileGrid, tileCoord, projection) {
6899 var z = tileCoord[0];
6900 var center = tileGrid.getTileCoordCenter(tileCoord);
6901 var projectionExtent = ol.tilegrid.extentFromProjection(projection);
6902 if (!ol.extent.containsCoordinate(projectionExtent, center)) {
6903 var worldWidth = ol.extent.getWidth(projectionExtent);
6904 var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth);
6905 center[0] += worldWidth * worldsAway;
6906 return tileGrid.getTileCoordForCoordAndZ(center, z);
6907 } else {
6908 return tileCoord;
6909 }
6910};
6911
6912
6913/**
6914 * @param {ol.Extent} extent Extent.
6915 * @param {number=} opt_maxZoom Maximum zoom level (default is
6916 * ol.DEFAULT_MAX_ZOOM).
6917 * @param {number|ol.Size=} opt_tileSize Tile size (default uses
6918 * ol.DEFAULT_TILE_SIZE).
6919 * @param {ol.extent.Corner=} opt_corner Extent corner (default is
6920 * ol.extent.Corner.TOP_LEFT).
6921 * @return {!ol.tilegrid.TileGrid} TileGrid instance.
6922 */
6923ol.tilegrid.createForExtent = function(extent, opt_maxZoom, opt_tileSize, opt_corner) {
6924 var corner = opt_corner !== undefined ?
6925 opt_corner : ol.extent.Corner.TOP_LEFT;
6926
6927 var resolutions = ol.tilegrid.resolutionsFromExtent(
6928 extent, opt_maxZoom, opt_tileSize);
6929
6930 return new ol.tilegrid.TileGrid({
6931 extent: extent,
6932 origin: ol.extent.getCorner(extent, corner),
6933 resolutions: resolutions,
6934 tileSize: opt_tileSize
6935 });
6936};
6937
6938
6939/**
6940 * Creates a tile grid with a standard XYZ tiling scheme.
6941 * @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.
6942 * @return {!ol.tilegrid.TileGrid} Tile grid instance.
6943 * @api
6944 */
6945ol.tilegrid.createXYZ = function(opt_options) {
6946 var options = /** @type {olx.tilegrid.TileGridOptions} */ ({});
6947 ol.obj.assign(options, opt_options !== undefined ?
6948 opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({}));
6949 if (options.extent === undefined) {
6950 options.extent = ol.proj.get('EPSG:3857').getExtent();
6951 }
6952 options.resolutions = ol.tilegrid.resolutionsFromExtent(
6953 options.extent, options.maxZoom, options.tileSize);
6954 delete options.maxZoom;
6955
6956 return new ol.tilegrid.TileGrid(options);
6957};
6958
6959
6960/**
6961 * Create a resolutions array from an extent. A zoom factor of 2 is assumed.
6962 * @param {ol.Extent} extent Extent.
6963 * @param {number=} opt_maxZoom Maximum zoom level (default is
6964 * ol.DEFAULT_MAX_ZOOM).
6965 * @param {number|ol.Size=} opt_tileSize Tile size (default uses
6966 * ol.DEFAULT_TILE_SIZE).
6967 * @return {!Array.<number>} Resolutions array.
6968 */
6969ol.tilegrid.resolutionsFromExtent = function(extent, opt_maxZoom, opt_tileSize) {
6970 var maxZoom = opt_maxZoom !== undefined ?
6971 opt_maxZoom : ol.DEFAULT_MAX_ZOOM;
6972
6973 var height = ol.extent.getHeight(extent);
6974 var width = ol.extent.getWidth(extent);
6975
6976 var tileSize = ol.size.toSize(opt_tileSize !== undefined ?
6977 opt_tileSize : ol.DEFAULT_TILE_SIZE);
6978 var maxResolution = Math.max(
6979 width / tileSize[0], height / tileSize[1]);
6980
6981 var length = maxZoom + 1;
6982 var resolutions = new Array(length);
6983 for (var z = 0; z < length; ++z) {
6984 resolutions[z] = maxResolution / Math.pow(2, z);
6985 }
6986 return resolutions;
6987};
6988
6989
6990/**
6991 * @param {ol.ProjectionLike} projection Projection.
6992 * @param {number=} opt_maxZoom Maximum zoom level (default is
6993 * ol.DEFAULT_MAX_ZOOM).
6994 * @param {number|ol.Size=} opt_tileSize Tile size (default uses
6995 * ol.DEFAULT_TILE_SIZE).
6996 * @param {ol.extent.Corner=} opt_corner Extent corner (default is
6997 * ol.extent.Corner.BOTTOM_LEFT).
6998 * @return {!ol.tilegrid.TileGrid} TileGrid instance.
6999 */
7000ol.tilegrid.createForProjection = function(projection, opt_maxZoom, opt_tileSize, opt_corner) {
7001 var extent = ol.tilegrid.extentFromProjection(projection);
7002 return ol.tilegrid.createForExtent(
7003 extent, opt_maxZoom, opt_tileSize, opt_corner);
7004};
7005
7006
7007/**
7008 * Generate a tile grid extent from a projection. If the projection has an
7009 * extent, it is used. If not, a global extent is assumed.
7010 * @param {ol.ProjectionLike} projection Projection.
7011 * @return {ol.Extent} Extent.
7012 */
7013ol.tilegrid.extentFromProjection = function(projection) {
7014 projection = ol.proj.get(projection);
7015 var extent = projection.getExtent();
7016 if (!extent) {
7017 var half = 180 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
7018 projection.getMetersPerUnit();
7019 extent = ol.extent.createOrUpdate(-half, -half, half, half);
7020 }
7021 return extent;
7022};
7023
7024goog.provide('ol.Attribution');
7025
7026goog.require('ol.TileRange');
7027goog.require('ol.math');
7028goog.require('ol.tilegrid');
7029
7030
7031/**
7032 * @classdesc
7033 * An attribution for a layer source.
7034 *
7035 * Example:
7036 *
7037 * source: new ol.source.OSM({
7038 * attributions: [
7039 * new ol.Attribution({
7040 * html: 'All maps &copy; ' +
7041 * '<a href="https://www.opencyclemap.org/">OpenCycleMap</a>'
7042 * }),
7043 * ol.source.OSM.ATTRIBUTION
7044 * ],
7045 * ..
7046 *
7047 * @constructor
7048 * @param {olx.AttributionOptions} options Attribution options.
7049 * @struct
7050 * @api
7051 */
7052ol.Attribution = function(options) {
7053
7054 /**
7055 * @private
7056 * @type {string}
7057 */
7058 this.html_ = options.html;
7059
7060 /**
7061 * @private
7062 * @type {Object.<string, Array.<ol.TileRange>>}
7063 */
7064 this.tileRanges_ = options.tileRanges ? options.tileRanges : null;
7065
7066};
7067
7068
7069/**
7070 * Get the attribution markup.
7071 * @return {string} The attribution HTML.
7072 * @api
7073 */
7074ol.Attribution.prototype.getHTML = function() {
7075 return this.html_;
7076};
7077
7078
7079/**
7080 * @param {Object.<string, ol.TileRange>} tileRanges Tile ranges.
7081 * @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.
7082 * @param {!ol.proj.Projection} projection Projection.
7083 * @return {boolean} Intersects any tile range.
7084 */
7085ol.Attribution.prototype.intersectsAnyTileRange = function(tileRanges, tileGrid, projection) {
7086 if (!this.tileRanges_) {
7087 return true;
7088 }
7089 var i, ii, tileRange, zKey;
7090 for (zKey in tileRanges) {
7091 if (!(zKey in this.tileRanges_)) {
7092 continue;
7093 }
7094 tileRange = tileRanges[zKey];
7095 var testTileRange;
7096 for (i = 0, ii = this.tileRanges_[zKey].length; i < ii; ++i) {
7097 testTileRange = this.tileRanges_[zKey][i];
7098 if (testTileRange.intersects(tileRange)) {
7099 return true;
7100 }
7101 var extentTileRange = tileGrid.getTileRangeForExtentAndZ(
7102 ol.tilegrid.extentFromProjection(projection), parseInt(zKey, 10));
7103 var width = extentTileRange.getWidth();
7104 if (tileRange.minX < extentTileRange.minX ||
7105 tileRange.maxX > extentTileRange.maxX) {
7106 if (testTileRange.intersects(new ol.TileRange(
7107 ol.math.modulo(tileRange.minX, width),
7108 ol.math.modulo(tileRange.maxX, width),
7109 tileRange.minY, tileRange.maxY))) {
7110 return true;
7111 }
7112 if (tileRange.getWidth() > width &&
7113 testTileRange.intersects(extentTileRange)) {
7114 return true;
7115 }
7116 }
7117 }
7118 }
7119 return false;
7120};
7121
7122goog.provide('ol.CenterConstraint');
7123
7124goog.require('ol.math');
7125
7126
7127/**
7128 * @param {ol.Extent} extent Extent.
7129 * @return {ol.CenterConstraintType} The constraint.
7130 */
7131ol.CenterConstraint.createExtent = function(extent) {
7132 return (
7133 /**
7134 * @param {ol.Coordinate|undefined} center Center.
7135 * @return {ol.Coordinate|undefined} Center.
7136 */
7137 function(center) {
7138 if (center) {
7139 return [
7140 ol.math.clamp(center[0], extent[0], extent[2]),
7141 ol.math.clamp(center[1], extent[1], extent[3])
7142 ];
7143 } else {
7144 return undefined;
7145 }
7146 });
7147};
7148
7149
7150/**
7151 * @param {ol.Coordinate|undefined} center Center.
7152 * @return {ol.Coordinate|undefined} Center.
7153 */
7154ol.CenterConstraint.none = function(center) {
7155 return center;
7156};
7157
7158goog.provide('ol.CollectionEventType');
7159
7160/**
7161 * @enum {string}
7162 */
7163ol.CollectionEventType = {
7164 /**
7165 * Triggered when an item is added to the collection.
7166 * @event ol.Collection.Event#add
7167 * @api
7168 */
7169 ADD: 'add',
7170 /**
7171 * Triggered when an item is removed from the collection.
7172 * @event ol.Collection.Event#remove
7173 * @api
7174 */
7175 REMOVE: 'remove'
7176};
7177
7178goog.provide('ol.ObjectEventType');
7179
7180/**
7181 * @enum {string}
7182 */
7183ol.ObjectEventType = {
7184 /**
7185 * Triggered when a property is changed.
7186 * @event ol.Object.Event#propertychange
7187 * @api
7188 */
7189 PROPERTYCHANGE: 'propertychange'
7190};
7191
7192goog.provide('ol.events');
7193
7194goog.require('ol.obj');
7195
7196
7197/**
7198 * @param {ol.EventsKey} listenerObj Listener object.
7199 * @return {ol.EventsListenerFunctionType} Bound listener.
7200 */
7201ol.events.bindListener_ = function(listenerObj) {
7202 var boundListener = function(evt) {
7203 var listener = listenerObj.listener;
7204 var bindTo = listenerObj.bindTo || listenerObj.target;
7205 if (listenerObj.callOnce) {
7206 ol.events.unlistenByKey(listenerObj);
7207 }
7208 return listener.call(bindTo, evt);
7209 };
7210 listenerObj.boundListener = boundListener;
7211 return boundListener;
7212};
7213
7214
7215/**
7216 * Finds the matching {@link ol.EventsKey} in the given listener
7217 * array.
7218 *
7219 * @param {!Array<!ol.EventsKey>} listeners Array of listeners.
7220 * @param {!Function} listener The listener function.
7221 * @param {Object=} opt_this The `this` value inside the listener.
7222 * @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching
7223 * listener, for {@link ol.events.unlistenByKey}.
7224 * @return {ol.EventsKey|undefined} The matching listener object.
7225 * @private
7226 */
7227ol.events.findListener_ = function(listeners, listener, opt_this,
7228 opt_setDeleteIndex) {
7229 var listenerObj;
7230 for (var i = 0, ii = listeners.length; i < ii; ++i) {
7231 listenerObj = listeners[i];
7232 if (listenerObj.listener === listener &&
7233 listenerObj.bindTo === opt_this) {
7234 if (opt_setDeleteIndex) {
7235 listenerObj.deleteIndex = i;
7236 }
7237 return listenerObj;
7238 }
7239 }
7240 return undefined;
7241};
7242
7243
7244/**
7245 * @param {ol.EventTargetLike} target Target.
7246 * @param {string} type Type.
7247 * @return {Array.<ol.EventsKey>|undefined} Listeners.
7248 */
7249ol.events.getListeners = function(target, type) {
7250 var listenerMap = target.ol_lm;
7251 return listenerMap ? listenerMap[type] : undefined;
7252};
7253
7254
7255/**
7256 * Get the lookup of listeners. If one does not exist on the target, it is
7257 * created.
7258 * @param {ol.EventTargetLike} target Target.
7259 * @return {!Object.<string, Array.<ol.EventsKey>>} Map of
7260 * listeners by event type.
7261 * @private
7262 */
7263ol.events.getListenerMap_ = function(target) {
7264 var listenerMap = target.ol_lm;
7265 if (!listenerMap) {
7266 listenerMap = target.ol_lm = {};
7267 }
7268 return listenerMap;
7269};
7270
7271
7272/**
7273 * Clean up all listener objects of the given type. All properties on the
7274 * listener objects will be removed, and if no listeners remain in the listener
7275 * map, it will be removed from the target.
7276 * @param {ol.EventTargetLike} target Target.
7277 * @param {string} type Type.
7278 * @private
7279 */
7280ol.events.removeListeners_ = function(target, type) {
7281 var listeners = ol.events.getListeners(target, type);
7282 if (listeners) {
7283 for (var i = 0, ii = listeners.length; i < ii; ++i) {
7284 target.removeEventListener(type, listeners[i].boundListener);
7285 ol.obj.clear(listeners[i]);
7286 }
7287 listeners.length = 0;
7288 var listenerMap = target.ol_lm;
7289 if (listenerMap) {
7290 delete listenerMap[type];
7291 if (Object.keys(listenerMap).length === 0) {
7292 delete target.ol_lm;
7293 }
7294 }
7295 }
7296};
7297
7298
7299/**
7300 * Registers an event listener on an event target. Inspired by
7301 * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
7302 *
7303 * This function efficiently binds a `listener` to a `this` object, and returns
7304 * a key for use with {@link ol.events.unlistenByKey}.
7305 *
7306 * @param {ol.EventTargetLike} target Event target.
7307 * @param {string} type Event type.
7308 * @param {ol.EventsListenerFunctionType} listener Listener.
7309 * @param {Object=} opt_this Object referenced by the `this` keyword in the
7310 * listener. Default is the `target`.
7311 * @param {boolean=} opt_once If true, add the listener as one-off listener.
7312 * @return {ol.EventsKey} Unique key for the listener.
7313 */
7314ol.events.listen = function(target, type, listener, opt_this, opt_once) {
7315 var listenerMap = ol.events.getListenerMap_(target);
7316 var listeners = listenerMap[type];
7317 if (!listeners) {
7318 listeners = listenerMap[type] = [];
7319 }
7320 var listenerObj = ol.events.findListener_(listeners, listener, opt_this,
7321 false);
7322 if (listenerObj) {
7323 if (!opt_once) {
7324 // Turn one-off listener into a permanent one.
7325 listenerObj.callOnce = false;
7326 }
7327 } else {
7328 listenerObj = /** @type {ol.EventsKey} */ ({
7329 bindTo: opt_this,
7330 callOnce: !!opt_once,
7331 listener: listener,
7332 target: target,
7333 type: type
7334 });
7335 target.addEventListener(type, ol.events.bindListener_(listenerObj));
7336 listeners.push(listenerObj);
7337 }
7338
7339 return listenerObj;
7340};
7341
7342
7343/**
7344 * Registers a one-off event listener on an event target. Inspired by
7345 * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
7346 *
7347 * This function efficiently binds a `listener` as self-unregistering listener
7348 * to a `this` object, and returns a key for use with
7349 * {@link ol.events.unlistenByKey} in case the listener needs to be unregistered
7350 * before it is called.
7351 *
7352 * When {@link ol.events.listen} is called with the same arguments after this
7353 * function, the self-unregistering listener will be turned into a permanent
7354 * listener.
7355 *
7356 * @param {ol.EventTargetLike} target Event target.
7357 * @param {string} type Event type.
7358 * @param {ol.EventsListenerFunctionType} listener Listener.
7359 * @param {Object=} opt_this Object referenced by the `this` keyword in the
7360 * listener. Default is the `target`.
7361 * @return {ol.EventsKey} Key for unlistenByKey.
7362 */
7363ol.events.listenOnce = function(target, type, listener, opt_this) {
7364 return ol.events.listen(target, type, listener, opt_this, true);
7365};
7366
7367
7368/**
7369 * Unregisters an event listener on an event target. Inspired by
7370 * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
7371 *
7372 * To return a listener, this function needs to be called with the exact same
7373 * arguments that were used for a previous {@link ol.events.listen} call.
7374 *
7375 * @param {ol.EventTargetLike} target Event target.
7376 * @param {string} type Event type.
7377 * @param {ol.EventsListenerFunctionType} listener Listener.
7378 * @param {Object=} opt_this Object referenced by the `this` keyword in the
7379 * listener. Default is the `target`.
7380 */
7381ol.events.unlisten = function(target, type, listener, opt_this) {
7382 var listeners = ol.events.getListeners(target, type);
7383 if (listeners) {
7384 var listenerObj = ol.events.findListener_(listeners, listener, opt_this,
7385 true);
7386 if (listenerObj) {
7387 ol.events.unlistenByKey(listenerObj);
7388 }
7389 }
7390};
7391
7392
7393/**
7394 * Unregisters event listeners on an event target. Inspired by
7395 * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
7396 *
7397 * The argument passed to this function is the key returned from
7398 * {@link ol.events.listen} or {@link ol.events.listenOnce}.
7399 *
7400 * @param {ol.EventsKey} key The key.
7401 */
7402ol.events.unlistenByKey = function(key) {
7403 if (key && key.target) {
7404 key.target.removeEventListener(key.type, key.boundListener);
7405 var listeners = ol.events.getListeners(key.target, key.type);
7406 if (listeners) {
7407 var i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);
7408 if (i !== -1) {
7409 listeners.splice(i, 1);
7410 }
7411 if (listeners.length === 0) {
7412 ol.events.removeListeners_(key.target, key.type);
7413 }
7414 }
7415 ol.obj.clear(key);
7416 }
7417};
7418
7419
7420/**
7421 * Unregisters all event listeners on an event target. Inspired by
7422 * {@link https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html}
7423 *
7424 * @param {ol.EventTargetLike} target Target.
7425 */
7426ol.events.unlistenAll = function(target) {
7427 var listenerMap = ol.events.getListenerMap_(target);
7428 for (var type in listenerMap) {
7429 ol.events.removeListeners_(target, type);
7430 }
7431};
7432
7433goog.provide('ol.Disposable');
7434
7435goog.require('ol');
7436
7437/**
7438 * Objects that need to clean up after themselves.
7439 * @constructor
7440 */
7441ol.Disposable = function() {};
7442
7443/**
7444 * The object has already been disposed.
7445 * @type {boolean}
7446 * @private
7447 */
7448ol.Disposable.prototype.disposed_ = false;
7449
7450/**
7451 * Clean up.
7452 */
7453ol.Disposable.prototype.dispose = function() {
7454 if (!this.disposed_) {
7455 this.disposed_ = true;
7456 this.disposeInternal();
7457 }
7458};
7459
7460/**
7461 * Extension point for disposable objects.
7462 * @protected
7463 */
7464ol.Disposable.prototype.disposeInternal = ol.nullFunction;
7465
7466goog.provide('ol.events.Event');
7467
7468
7469/**
7470 * @classdesc
7471 * Stripped down implementation of the W3C DOM Level 2 Event interface.
7472 * @see {@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface}
7473 *
7474 * This implementation only provides `type` and `target` properties, and
7475 * `stopPropagation` and `preventDefault` methods. It is meant as base class
7476 * for higher level events defined in the library, and works with
7477 * {@link ol.events.EventTarget}.
7478 *
7479 * @constructor
7480 * @implements {oli.events.Event}
7481 * @param {string} type Type.
7482 */
7483ol.events.Event = function(type) {
7484
7485 /**
7486 * @type {boolean}
7487 */
7488 this.propagationStopped;
7489
7490 /**
7491 * The event type.
7492 * @type {string}
7493 * @api
7494 */
7495 this.type = type;
7496
7497 /**
7498 * The event target.
7499 * @type {Object}
7500 * @api
7501 */
7502 this.target = null;
7503
7504};
7505
7506
7507/**
7508 * Stop event propagation.
7509 * @function
7510 * @override
7511 * @api
7512 */
7513ol.events.Event.prototype.preventDefault =
7514
7515 /**
7516 * Stop event propagation.
7517 * @function
7518 * @override
7519 * @api
7520 */
7521 ol.events.Event.prototype.stopPropagation = function() {
7522 this.propagationStopped = true;
7523 };
7524
7525
7526/**
7527 * @param {Event|ol.events.Event} evt Event
7528 */
7529ol.events.Event.stopPropagation = function(evt) {
7530 evt.stopPropagation();
7531};
7532
7533
7534/**
7535 * @param {Event|ol.events.Event} evt Event
7536 */
7537ol.events.Event.preventDefault = function(evt) {
7538 evt.preventDefault();
7539};
7540
7541goog.provide('ol.events.EventTarget');
7542
7543goog.require('ol');
7544goog.require('ol.Disposable');
7545goog.require('ol.events');
7546goog.require('ol.events.Event');
7547
7548
7549/**
7550 * @classdesc
7551 * A simplified implementation of the W3C DOM Level 2 EventTarget interface.
7552 * @see {@link https://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html#Events-EventTarget}
7553 *
7554 * There are two important simplifications compared to the specification:
7555 *
7556 * 1. The handling of `useCapture` in `addEventListener` and
7557 * `removeEventListener`. There is no real capture model.
7558 * 2. The handling of `stopPropagation` and `preventDefault` on `dispatchEvent`.
7559 * There is no event target hierarchy. When a listener calls
7560 * `stopPropagation` or `preventDefault` on an event object, it means that no
7561 * more listeners after this one will be called. Same as when the listener
7562 * returns false.
7563 *
7564 * @constructor
7565 * @extends {ol.Disposable}
7566 */
7567ol.events.EventTarget = function() {
7568
7569 ol.Disposable.call(this);
7570
7571 /**
7572 * @private
7573 * @type {!Object.<string, number>}
7574 */
7575 this.pendingRemovals_ = {};
7576
7577 /**
7578 * @private
7579 * @type {!Object.<string, number>}
7580 */
7581 this.dispatching_ = {};
7582
7583 /**
7584 * @private
7585 * @type {!Object.<string, Array.<ol.EventsListenerFunctionType>>}
7586 */
7587 this.listeners_ = {};
7588
7589};
7590ol.inherits(ol.events.EventTarget, ol.Disposable);
7591
7592
7593/**
7594 * @param {string} type Type.
7595 * @param {ol.EventsListenerFunctionType} listener Listener.
7596 */
7597ol.events.EventTarget.prototype.addEventListener = function(type, listener) {
7598 var listeners = this.listeners_[type];
7599 if (!listeners) {
7600 listeners = this.listeners_[type] = [];
7601 }
7602 if (listeners.indexOf(listener) === -1) {
7603 listeners.push(listener);
7604 }
7605};
7606
7607
7608/**
7609 * @param {{type: string,
7610 * target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|
7611 * string} event Event or event type.
7612 * @return {boolean|undefined} `false` if anyone called preventDefault on the
7613 * event object or if any of the listeners returned false.
7614 */
7615ol.events.EventTarget.prototype.dispatchEvent = function(event) {
7616 var evt = typeof event === 'string' ? new ol.events.Event(event) : event;
7617 var type = evt.type;
7618 evt.target = this;
7619 var listeners = this.listeners_[type];
7620 var propagate;
7621 if (listeners) {
7622 if (!(type in this.dispatching_)) {
7623 this.dispatching_[type] = 0;
7624 this.pendingRemovals_[type] = 0;
7625 }
7626 ++this.dispatching_[type];
7627 for (var i = 0, ii = listeners.length; i < ii; ++i) {
7628 if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
7629 propagate = false;
7630 break;
7631 }
7632 }
7633 --this.dispatching_[type];
7634 if (this.dispatching_[type] === 0) {
7635 var pendingRemovals = this.pendingRemovals_[type];
7636 delete this.pendingRemovals_[type];
7637 while (pendingRemovals--) {
7638 this.removeEventListener(type, ol.nullFunction);
7639 }
7640 delete this.dispatching_[type];
7641 }
7642 return propagate;
7643 }
7644};
7645
7646
7647/**
7648 * @inheritDoc
7649 */
7650ol.events.EventTarget.prototype.disposeInternal = function() {
7651 ol.events.unlistenAll(this);
7652};
7653
7654
7655/**
7656 * Get the listeners for a specified event type. Listeners are returned in the
7657 * order that they will be called in.
7658 *
7659 * @param {string} type Type.
7660 * @return {Array.<ol.EventsListenerFunctionType>} Listeners.
7661 */
7662ol.events.EventTarget.prototype.getListeners = function(type) {
7663 return this.listeners_[type];
7664};
7665
7666
7667/**
7668 * @param {string=} opt_type Type. If not provided,
7669 * `true` will be returned if this EventTarget has any listeners.
7670 * @return {boolean} Has listeners.
7671 */
7672ol.events.EventTarget.prototype.hasListener = function(opt_type) {
7673 return opt_type ?
7674 opt_type in this.listeners_ :
7675 Object.keys(this.listeners_).length > 0;
7676};
7677
7678
7679/**
7680 * @param {string} type Type.
7681 * @param {ol.EventsListenerFunctionType} listener Listener.
7682 */
7683ol.events.EventTarget.prototype.removeEventListener = function(type, listener) {
7684 var listeners = this.listeners_[type];
7685 if (listeners) {
7686 var index = listeners.indexOf(listener);
7687 if (type in this.pendingRemovals_) {
7688 // make listener a no-op, and remove later in #dispatchEvent()
7689 listeners[index] = ol.nullFunction;
7690 ++this.pendingRemovals_[type];
7691 } else {
7692 listeners.splice(index, 1);
7693 if (listeners.length === 0) {
7694 delete this.listeners_[type];
7695 }
7696 }
7697 }
7698};
7699
7700goog.provide('ol.events.EventType');
7701
7702/**
7703 * @enum {string}
7704 * @const
7705 */
7706ol.events.EventType = {
7707 /**
7708 * Generic change event. Triggered when the revision counter is increased.
7709 * @event ol.events.Event#change
7710 * @api
7711 */
7712 CHANGE: 'change',
7713
7714 CLICK: 'click',
7715 DBLCLICK: 'dblclick',
7716 DRAGENTER: 'dragenter',
7717 DRAGOVER: 'dragover',
7718 DROP: 'drop',
7719 ERROR: 'error',
7720 KEYDOWN: 'keydown',
7721 KEYPRESS: 'keypress',
7722 LOAD: 'load',
7723 MOUSEDOWN: 'mousedown',
7724 MOUSEMOVE: 'mousemove',
7725 MOUSEOUT: 'mouseout',
7726 MOUSEUP: 'mouseup',
7727 MOUSEWHEEL: 'mousewheel',
7728 MSPOINTERDOWN: 'MSPointerDown',
7729 RESIZE: 'resize',
7730 TOUCHSTART: 'touchstart',
7731 TOUCHMOVE: 'touchmove',
7732 TOUCHEND: 'touchend',
7733 WHEEL: 'wheel'
7734};
7735
7736goog.provide('ol.Observable');
7737
7738goog.require('ol');
7739goog.require('ol.events');
7740goog.require('ol.events.EventTarget');
7741goog.require('ol.events.EventType');
7742
7743
7744/**
7745 * @classdesc
7746 * Abstract base class; normally only used for creating subclasses and not
7747 * instantiated in apps.
7748 * An event target providing convenient methods for listener registration
7749 * and unregistration. A generic `change` event is always available through
7750 * {@link ol.Observable#changed}.
7751 *
7752 * @constructor
7753 * @extends {ol.events.EventTarget}
7754 * @fires ol.events.Event
7755 * @struct
7756 * @api
7757 */
7758ol.Observable = function() {
7759
7760 ol.events.EventTarget.call(this);
7761
7762 /**
7763 * @private
7764 * @type {number}
7765 */
7766 this.revision_ = 0;
7767
7768};
7769ol.inherits(ol.Observable, ol.events.EventTarget);
7770
7771
7772/**
7773 * Removes an event listener using the key returned by `on()` or `once()`.
7774 * @param {ol.EventsKey|Array.<ol.EventsKey>} key The key returned by `on()`
7775 * or `once()` (or an array of keys).
7776 * @api
7777 */
7778ol.Observable.unByKey = function(key) {
7779 if (Array.isArray(key)) {
7780 for (var i = 0, ii = key.length; i < ii; ++i) {
7781 ol.events.unlistenByKey(key[i]);
7782 }
7783 } else {
7784 ol.events.unlistenByKey(/** @type {ol.EventsKey} */ (key));
7785 }
7786};
7787
7788
7789/**
7790 * Increases the revision counter and dispatches a 'change' event.
7791 * @api
7792 */
7793ol.Observable.prototype.changed = function() {
7794 ++this.revision_;
7795 this.dispatchEvent(ol.events.EventType.CHANGE);
7796};
7797
7798
7799/**
7800 * Dispatches an event and calls all listeners listening for events
7801 * of this type. The event parameter can either be a string or an
7802 * Object with a `type` property.
7803 *
7804 * @param {{type: string,
7805 * target: (EventTarget|ol.events.EventTarget|undefined)}|ol.events.Event|
7806 * string} event Event object.
7807 * @function
7808 * @api
7809 */
7810ol.Observable.prototype.dispatchEvent;
7811
7812
7813/**
7814 * Get the version number for this object. Each time the object is modified,
7815 * its version number will be incremented.
7816 * @return {number} Revision.
7817 * @api
7818 */
7819ol.Observable.prototype.getRevision = function() {
7820 return this.revision_;
7821};
7822
7823
7824/**
7825 * Listen for a certain type of event.
7826 * @param {string|Array.<string>} type The event type or array of event types.
7827 * @param {function(?): ?} listener The listener function.
7828 * @param {Object=} opt_this The object to use as `this` in `listener`.
7829 * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If
7830 * called with an array of event types as the first argument, the return
7831 * will be an array of keys.
7832 * @api
7833 */
7834ol.Observable.prototype.on = function(type, listener, opt_this) {
7835 if (Array.isArray(type)) {
7836 var len = type.length;
7837 var keys = new Array(len);
7838 for (var i = 0; i < len; ++i) {
7839 keys[i] = ol.events.listen(this, type[i], listener, opt_this);
7840 }
7841 return keys;
7842 } else {
7843 return ol.events.listen(
7844 this, /** @type {string} */ (type), listener, opt_this);
7845 }
7846};
7847
7848
7849/**
7850 * Listen once for a certain type of event.
7851 * @param {string|Array.<string>} type The event type or array of event types.
7852 * @param {function(?): ?} listener The listener function.
7853 * @param {Object=} opt_this The object to use as `this` in `listener`.
7854 * @return {ol.EventsKey|Array.<ol.EventsKey>} Unique key for the listener. If
7855 * called with an array of event types as the first argument, the return
7856 * will be an array of keys.
7857 * @api
7858 */
7859ol.Observable.prototype.once = function(type, listener, opt_this) {
7860 if (Array.isArray(type)) {
7861 var len = type.length;
7862 var keys = new Array(len);
7863 for (var i = 0; i < len; ++i) {
7864 keys[i] = ol.events.listenOnce(this, type[i], listener, opt_this);
7865 }
7866 return keys;
7867 } else {
7868 return ol.events.listenOnce(
7869 this, /** @type {string} */ (type), listener, opt_this);
7870 }
7871};
7872
7873
7874/**
7875 * Unlisten for a certain type of event.
7876 * @param {string|Array.<string>} type The event type or array of event types.
7877 * @param {function(?): ?} listener The listener function.
7878 * @param {Object=} opt_this The object which was used as `this` by the
7879 * `listener`.
7880 * @api
7881 */
7882ol.Observable.prototype.un = function(type, listener, opt_this) {
7883 if (Array.isArray(type)) {
7884 for (var i = 0, ii = type.length; i < ii; ++i) {
7885 ol.events.unlisten(this, type[i], listener, opt_this);
7886 }
7887 return;
7888 } else {
7889 ol.events.unlisten(this, /** @type {string} */ (type), listener, opt_this);
7890 }
7891};
7892
7893goog.provide('ol.Object');
7894
7895goog.require('ol');
7896goog.require('ol.ObjectEventType');
7897goog.require('ol.Observable');
7898goog.require('ol.events.Event');
7899goog.require('ol.obj');
7900
7901
7902/**
7903 * @classdesc
7904 * Abstract base class; normally only used for creating subclasses and not
7905 * instantiated in apps.
7906 * Most non-trivial classes inherit from this.
7907 *
7908 * This extends {@link ol.Observable} with observable properties, where each
7909 * property is observable as well as the object as a whole.
7910 *
7911 * Classes that inherit from this have pre-defined properties, to which you can
7912 * add your owns. The pre-defined properties are listed in this documentation as
7913 * 'Observable Properties', and have their own accessors; for example,
7914 * {@link ol.Map} has a `target` property, accessed with `getTarget()` and
7915 * changed with `setTarget()`. Not all properties are however settable. There
7916 * are also general-purpose accessors `get()` and `set()`. For example,
7917 * `get('target')` is equivalent to `getTarget()`.
7918 *
7919 * The `set` accessors trigger a change event, and you can monitor this by
7920 * registering a listener. For example, {@link ol.View} has a `center`
7921 * property, so `view.on('change:center', function(evt) {...});` would call the
7922 * function whenever the value of the center property changes. Within the
7923 * function, `evt.target` would be the view, so `evt.target.getCenter()` would
7924 * return the new center.
7925 *
7926 * You can add your own observable properties with
7927 * `object.set('prop', 'value')`, and retrieve that with `object.get('prop')`.
7928 * You can listen for changes on that property value with
7929 * `object.on('change:prop', listener)`. You can get a list of all
7930 * properties with {@link ol.Object#getProperties object.getProperties()}.
7931 *
7932 * Note that the observable properties are separate from standard JS properties.
7933 * You can, for example, give your map object a title with
7934 * `map.title='New title'` and with `map.set('title', 'Another title')`. The
7935 * first will be a `hasOwnProperty`; the second will appear in
7936 * `getProperties()`. Only the second is observable.
7937 *
7938 * Properties can be deleted by using the unset method. E.g.
7939 * object.unset('foo').
7940 *
7941 * @constructor
7942 * @extends {ol.Observable}
7943 * @param {Object.<string, *>=} opt_values An object with key-value pairs.
7944 * @fires ol.Object.Event
7945 * @api
7946 */
7947ol.Object = function(opt_values) {
7948 ol.Observable.call(this);
7949
7950 // Call ol.getUid to ensure that the order of objects' ids is the same as
7951 // the order in which they were created. This also helps to ensure that
7952 // object properties are always added in the same order, which helps many
7953 // JavaScript engines generate faster code.
7954 ol.getUid(this);
7955
7956 /**
7957 * @private
7958 * @type {!Object.<string, *>}
7959 */
7960 this.values_ = {};
7961
7962 if (opt_values !== undefined) {
7963 this.setProperties(opt_values);
7964 }
7965};
7966ol.inherits(ol.Object, ol.Observable);
7967
7968
7969/**
7970 * @private
7971 * @type {Object.<string, string>}
7972 */
7973ol.Object.changeEventTypeCache_ = {};
7974
7975
7976/**
7977 * @param {string} key Key name.
7978 * @return {string} Change name.
7979 */
7980ol.Object.getChangeEventType = function(key) {
7981 return ol.Object.changeEventTypeCache_.hasOwnProperty(key) ?
7982 ol.Object.changeEventTypeCache_[key] :
7983 (ol.Object.changeEventTypeCache_[key] = 'change:' + key);
7984};
7985
7986
7987/**
7988 * Gets a value.
7989 * @param {string} key Key name.
7990 * @return {*} Value.
7991 * @api
7992 */
7993ol.Object.prototype.get = function(key) {
7994 var value;
7995 if (this.values_.hasOwnProperty(key)) {
7996 value = this.values_[key];
7997 }
7998 return value;
7999};
8000
8001
8002/**
8003 * Get a list of object property names.
8004 * @return {Array.<string>} List of property names.
8005 * @api
8006 */
8007ol.Object.prototype.getKeys = function() {
8008 return Object.keys(this.values_);
8009};
8010
8011
8012/**
8013 * Get an object of all property names and values.
8014 * @return {Object.<string, *>} Object.
8015 * @api
8016 */
8017ol.Object.prototype.getProperties = function() {
8018 return ol.obj.assign({}, this.values_);
8019};
8020
8021
8022/**
8023 * @param {string} key Key name.
8024 * @param {*} oldValue Old value.
8025 */
8026ol.Object.prototype.notify = function(key, oldValue) {
8027 var eventType;
8028 eventType = ol.Object.getChangeEventType(key);
8029 this.dispatchEvent(new ol.Object.Event(eventType, key, oldValue));
8030 eventType = ol.ObjectEventType.PROPERTYCHANGE;
8031 this.dispatchEvent(new ol.Object.Event(eventType, key, oldValue));
8032};
8033
8034
8035/**
8036 * Sets a value.
8037 * @param {string} key Key name.
8038 * @param {*} value Value.
8039 * @param {boolean=} opt_silent Update without triggering an event.
8040 * @api
8041 */
8042ol.Object.prototype.set = function(key, value, opt_silent) {
8043 if (opt_silent) {
8044 this.values_[key] = value;
8045 } else {
8046 var oldValue = this.values_[key];
8047 this.values_[key] = value;
8048 if (oldValue !== value) {
8049 this.notify(key, oldValue);
8050 }
8051 }
8052};
8053
8054
8055/**
8056 * Sets a collection of key-value pairs. Note that this changes any existing
8057 * properties and adds new ones (it does not remove any existing properties).
8058 * @param {Object.<string, *>} values Values.
8059 * @param {boolean=} opt_silent Update without triggering an event.
8060 * @api
8061 */
8062ol.Object.prototype.setProperties = function(values, opt_silent) {
8063 var key;
8064 for (key in values) {
8065 this.set(key, values[key], opt_silent);
8066 }
8067};
8068
8069
8070/**
8071 * Unsets a property.
8072 * @param {string} key Key name.
8073 * @param {boolean=} opt_silent Unset without triggering an event.
8074 * @api
8075 */
8076ol.Object.prototype.unset = function(key, opt_silent) {
8077 if (key in this.values_) {
8078 var oldValue = this.values_[key];
8079 delete this.values_[key];
8080 if (!opt_silent) {
8081 this.notify(key, oldValue);
8082 }
8083 }
8084};
8085
8086
8087/**
8088 * @classdesc
8089 * Events emitted by {@link ol.Object} instances are instances of this type.
8090 *
8091 * @param {string} type The event type.
8092 * @param {string} key The property name.
8093 * @param {*} oldValue The old value for `key`.
8094 * @extends {ol.events.Event}
8095 * @implements {oli.Object.Event}
8096 * @constructor
8097 */
8098ol.Object.Event = function(type, key, oldValue) {
8099 ol.events.Event.call(this, type);
8100
8101 /**
8102 * The name of the property whose value is changing.
8103 * @type {string}
8104 * @api
8105 */
8106 this.key = key;
8107
8108 /**
8109 * The old value. To get the new value use `e.target.get(e.key)` where
8110 * `e` is the event object.
8111 * @type {*}
8112 * @api
8113 */
8114 this.oldValue = oldValue;
8115
8116};
8117ol.inherits(ol.Object.Event, ol.events.Event);
8118
8119/**
8120 * An implementation of Google Maps' MVCArray.
8121 * @see https://developers.google.com/maps/documentation/javascript/reference
8122 */
8123
8124goog.provide('ol.Collection');
8125
8126goog.require('ol');
8127goog.require('ol.AssertionError');
8128goog.require('ol.CollectionEventType');
8129goog.require('ol.Object');
8130goog.require('ol.events.Event');
8131
8132
8133/**
8134 * @classdesc
8135 * An expanded version of standard JS Array, adding convenience methods for
8136 * manipulation. Add and remove changes to the Collection trigger a Collection
8137 * event. Note that this does not cover changes to the objects _within_ the
8138 * Collection; they trigger events on the appropriate object, not on the
8139 * Collection as a whole.
8140 *
8141 * @constructor
8142 * @extends {ol.Object}
8143 * @fires ol.Collection.Event
8144 * @param {Array.<T>=} opt_array Array.
8145 * @param {olx.CollectionOptions=} opt_options Collection options.
8146 * @template T
8147 * @api
8148 */
8149ol.Collection = function(opt_array, opt_options) {
8150
8151 ol.Object.call(this);
8152
8153 var options = opt_options || {};
8154
8155 /**
8156 * @private
8157 * @type {boolean}
8158 */
8159 this.unique_ = !!options.unique;
8160
8161 /**
8162 * @private
8163 * @type {!Array.<T>}
8164 */
8165 this.array_ = opt_array ? opt_array : [];
8166
8167 if (this.unique_) {
8168 for (var i = 0, ii = this.array_.length; i < ii; ++i) {
8169 this.assertUnique_(this.array_[i], i);
8170 }
8171 }
8172
8173 this.updateLength_();
8174
8175};
8176ol.inherits(ol.Collection, ol.Object);
8177
8178
8179/**
8180 * Remove all elements from the collection.
8181 * @api
8182 */
8183ol.Collection.prototype.clear = function() {
8184 while (this.getLength() > 0) {
8185 this.pop();
8186 }
8187};
8188
8189
8190/**
8191 * Add elements to the collection. This pushes each item in the provided array
8192 * to the end of the collection.
8193 * @param {!Array.<T>} arr Array.
8194 * @return {ol.Collection.<T>} This collection.
8195 * @api
8196 */
8197ol.Collection.prototype.extend = function(arr) {
8198 var i, ii;
8199 for (i = 0, ii = arr.length; i < ii; ++i) {
8200 this.push(arr[i]);
8201 }
8202 return this;
8203};
8204
8205
8206/**
8207 * Iterate over each element, calling the provided callback.
8208 * @param {function(this: S, T, number, Array.<T>): *} f The function to call
8209 * for every element. This function takes 3 arguments (the element, the
8210 * index and the array). The return value is ignored.
8211 * @param {S=} opt_this The object to use as `this` in `f`.
8212 * @template S
8213 * @api
8214 */
8215ol.Collection.prototype.forEach = function(f, opt_this) {
8216 var fn = (opt_this) ? f.bind(opt_this) : f;
8217 var array = this.array_;
8218 for (var i = 0, ii = array.length; i < ii; ++i) {
8219 fn(array[i], i, array);
8220 }
8221};
8222
8223
8224/**
8225 * Get a reference to the underlying Array object. Warning: if the array
8226 * is mutated, no events will be dispatched by the collection, and the
8227 * collection's "length" property won't be in sync with the actual length
8228 * of the array.
8229 * @return {!Array.<T>} Array.
8230 * @api
8231 */
8232ol.Collection.prototype.getArray = function() {
8233 return this.array_;
8234};
8235
8236
8237/**
8238 * Get the element at the provided index.
8239 * @param {number} index Index.
8240 * @return {T} Element.
8241 * @api
8242 */
8243ol.Collection.prototype.item = function(index) {
8244 return this.array_[index];
8245};
8246
8247
8248/**
8249 * Get the length of this collection.
8250 * @return {number} The length of the array.
8251 * @observable
8252 * @api
8253 */
8254ol.Collection.prototype.getLength = function() {
8255 return /** @type {number} */ (this.get(ol.Collection.Property_.LENGTH));
8256};
8257
8258
8259/**
8260 * Insert an element at the provided index.
8261 * @param {number} index Index.
8262 * @param {T} elem Element.
8263 * @api
8264 */
8265ol.Collection.prototype.insertAt = function(index, elem) {
8266 if (this.unique_) {
8267 this.assertUnique_(elem);
8268 }
8269 this.array_.splice(index, 0, elem);
8270 this.updateLength_();
8271 this.dispatchEvent(
8272 new ol.Collection.Event(ol.CollectionEventType.ADD, elem));
8273};
8274
8275
8276/**
8277 * Remove the last element of the collection and return it.
8278 * Return `undefined` if the collection is empty.
8279 * @return {T|undefined} Element.
8280 * @api
8281 */
8282ol.Collection.prototype.pop = function() {
8283 return this.removeAt(this.getLength() - 1);
8284};
8285
8286
8287/**
8288 * Insert the provided element at the end of the collection.
8289 * @param {T} elem Element.
8290 * @return {number} New length of the collection.
8291 * @api
8292 */
8293ol.Collection.prototype.push = function(elem) {
8294 if (this.unique_) {
8295 this.assertUnique_(elem);
8296 }
8297 var n = this.getLength();
8298 this.insertAt(n, elem);
8299 return this.getLength();
8300};
8301
8302
8303/**
8304 * Remove the first occurrence of an element from the collection.
8305 * @param {T} elem Element.
8306 * @return {T|undefined} The removed element or undefined if none found.
8307 * @api
8308 */
8309ol.Collection.prototype.remove = function(elem) {
8310 var arr = this.array_;
8311 var i, ii;
8312 for (i = 0, ii = arr.length; i < ii; ++i) {
8313 if (arr[i] === elem) {
8314 return this.removeAt(i);
8315 }
8316 }
8317 return undefined;
8318};
8319
8320
8321/**
8322 * Remove the element at the provided index and return it.
8323 * Return `undefined` if the collection does not contain this index.
8324 * @param {number} index Index.
8325 * @return {T|undefined} Value.
8326 * @api
8327 */
8328ol.Collection.prototype.removeAt = function(index) {
8329 var prev = this.array_[index];
8330 this.array_.splice(index, 1);
8331 this.updateLength_();
8332 this.dispatchEvent(
8333 new ol.Collection.Event(ol.CollectionEventType.REMOVE, prev));
8334 return prev;
8335};
8336
8337
8338/**
8339 * Set the element at the provided index.
8340 * @param {number} index Index.
8341 * @param {T} elem Element.
8342 * @api
8343 */
8344ol.Collection.prototype.setAt = function(index, elem) {
8345 var n = this.getLength();
8346 if (index < n) {
8347 if (this.unique_) {
8348 this.assertUnique_(elem, index);
8349 }
8350 var prev = this.array_[index];
8351 this.array_[index] = elem;
8352 this.dispatchEvent(
8353 new ol.Collection.Event(ol.CollectionEventType.REMOVE, prev));
8354 this.dispatchEvent(
8355 new ol.Collection.Event(ol.CollectionEventType.ADD, elem));
8356 } else {
8357 var j;
8358 for (j = n; j < index; ++j) {
8359 this.insertAt(j, undefined);
8360 }
8361 this.insertAt(index, elem);
8362 }
8363};
8364
8365
8366/**
8367 * @private
8368 */
8369ol.Collection.prototype.updateLength_ = function() {
8370 this.set(ol.Collection.Property_.LENGTH, this.array_.length);
8371};
8372
8373
8374/**
8375 * @private
8376 * @param {T} elem Element.
8377 * @param {number=} opt_except Optional index to ignore.
8378 */
8379ol.Collection.prototype.assertUnique_ = function(elem, opt_except) {
8380 for (var i = 0, ii = this.array_.length; i < ii; ++i) {
8381 if (this.array_[i] === elem && i !== opt_except) {
8382 throw new ol.AssertionError(58);
8383 }
8384 }
8385};
8386
8387
8388/**
8389 * @enum {string}
8390 * @private
8391 */
8392ol.Collection.Property_ = {
8393 LENGTH: 'length'
8394};
8395
8396
8397/**
8398 * @classdesc
8399 * Events emitted by {@link ol.Collection} instances are instances of this
8400 * type.
8401 *
8402 * @constructor
8403 * @extends {ol.events.Event}
8404 * @implements {oli.Collection.Event}
8405 * @param {ol.CollectionEventType} type Type.
8406 * @param {*=} opt_element Element.
8407 */
8408ol.Collection.Event = function(type, opt_element) {
8409
8410 ol.events.Event.call(this, type);
8411
8412 /**
8413 * The element that is added to or removed from the collection.
8414 * @type {*}
8415 * @api
8416 */
8417 this.element = opt_element;
8418
8419};
8420ol.inherits(ol.Collection.Event, ol.events.Event);
8421
8422goog.provide('ol.color');
8423
8424goog.require('ol.asserts');
8425goog.require('ol.math');
8426
8427
8428/**
8429 * This RegExp matches # followed by 3 or 6 hex digits.
8430 * @const
8431 * @type {RegExp}
8432 * @private
8433 */
8434ol.color.HEX_COLOR_RE_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
8435
8436
8437/**
8438 * Regular expression for matching potential named color style strings.
8439 * @const
8440 * @type {RegExp}
8441 * @private
8442 */
8443ol.color.NAMED_COLOR_RE_ = /^([a-z]*)$/i;
8444
8445
8446/**
8447 * Return the color as an array. This function maintains a cache of calculated
8448 * arrays which means the result should not be modified.
8449 * @param {ol.Color|string} color Color.
8450 * @return {ol.Color} Color.
8451 * @api
8452 */
8453ol.color.asArray = function(color) {
8454 if (Array.isArray(color)) {
8455 return color;
8456 } else {
8457 return ol.color.fromString(/** @type {string} */ (color));
8458 }
8459};
8460
8461
8462/**
8463 * Return the color as an rgba string.
8464 * @param {ol.Color|string} color Color.
8465 * @return {string} Rgba string.
8466 * @api
8467 */
8468ol.color.asString = function(color) {
8469 if (typeof color === 'string') {
8470 return color;
8471 } else {
8472 return ol.color.toString(color);
8473 }
8474};
8475
8476/**
8477 * Return named color as an rgba string.
8478 * @param {string} color Named color.
8479 * @return {string} Rgb string.
8480 */
8481ol.color.fromNamed = function(color) {
8482 var el = document.createElement('div');
8483 el.style.color = color;
8484 document.body.appendChild(el);
8485 var rgb = getComputedStyle(el).color;
8486 document.body.removeChild(el);
8487 return rgb;
8488};
8489
8490
8491/**
8492 * @param {string} s String.
8493 * @return {ol.Color} Color.
8494 */
8495ol.color.fromString = (
8496 function() {
8497
8498 // We maintain a small cache of parsed strings. To provide cheap LRU-like
8499 // semantics, whenever the cache grows too large we simply delete an
8500 // arbitrary 25% of the entries.
8501
8502 /**
8503 * @const
8504 * @type {number}
8505 */
8506 var MAX_CACHE_SIZE = 1024;
8507
8508 /**
8509 * @type {Object.<string, ol.Color>}
8510 */
8511 var cache = {};
8512
8513 /**
8514 * @type {number}
8515 */
8516 var cacheSize = 0;
8517
8518 return (
8519 /**
8520 * @param {string} s String.
8521 * @return {ol.Color} Color.
8522 */
8523 function(s) {
8524 var color;
8525 if (cache.hasOwnProperty(s)) {
8526 color = cache[s];
8527 } else {
8528 if (cacheSize >= MAX_CACHE_SIZE) {
8529 var i = 0;
8530 var key;
8531 for (key in cache) {
8532 if ((i++ & 3) === 0) {
8533 delete cache[key];
8534 --cacheSize;
8535 }
8536 }
8537 }
8538 color = ol.color.fromStringInternal_(s);
8539 cache[s] = color;
8540 ++cacheSize;
8541 }
8542 return color;
8543 });
8544
8545 })();
8546
8547
8548/**
8549 * @param {string} s String.
8550 * @private
8551 * @return {ol.Color} Color.
8552 */
8553ol.color.fromStringInternal_ = function(s) {
8554 var r, g, b, a, color, parts;
8555
8556 if (ol.color.NAMED_COLOR_RE_.exec(s)) {
8557 s = ol.color.fromNamed(s);
8558 }
8559
8560 if (ol.color.HEX_COLOR_RE_.exec(s)) { // hex
8561 var n = s.length - 1; // number of hex digits
8562 ol.asserts.assert(n == 3 || n == 6, 54); // Hex color should have 3 or 6 digits
8563 var d = n == 3 ? 1 : 2; // number of digits per channel
8564 r = parseInt(s.substr(1 + 0 * d, d), 16);
8565 g = parseInt(s.substr(1 + 1 * d, d), 16);
8566 b = parseInt(s.substr(1 + 2 * d, d), 16);
8567 if (d == 1) {
8568 r = (r << 4) + r;
8569 g = (g << 4) + g;
8570 b = (b << 4) + b;
8571 }
8572 a = 1;
8573 color = [r, g, b, a];
8574 } else if (s.indexOf('rgba(') == 0) { // rgba()
8575 parts = s.slice(5, -1).split(',').map(Number);
8576 color = ol.color.normalize(parts);
8577 } else if (s.indexOf('rgb(') == 0) { // rgb()
8578 parts = s.slice(4, -1).split(',').map(Number);
8579 parts.push(1);
8580 color = ol.color.normalize(parts);
8581 } else {
8582 ol.asserts.assert(false, 14); // Invalid color
8583 }
8584 return /** @type {ol.Color} */ (color);
8585};
8586
8587
8588/**
8589 * @param {ol.Color} color Color.
8590 * @param {ol.Color=} opt_color Color.
8591 * @return {ol.Color} Clamped color.
8592 */
8593ol.color.normalize = function(color, opt_color) {
8594 var result = opt_color || [];
8595 result[0] = ol.math.clamp((color[0] + 0.5) | 0, 0, 255);
8596 result[1] = ol.math.clamp((color[1] + 0.5) | 0, 0, 255);
8597 result[2] = ol.math.clamp((color[2] + 0.5) | 0, 0, 255);
8598 result[3] = ol.math.clamp(color[3], 0, 1);
8599 return result;
8600};
8601
8602
8603/**
8604 * @param {ol.Color} color Color.
8605 * @return {string} String.
8606 */
8607ol.color.toString = function(color) {
8608 var r = color[0];
8609 if (r != (r | 0)) {
8610 r = (r + 0.5) | 0;
8611 }
8612 var g = color[1];
8613 if (g != (g | 0)) {
8614 g = (g + 0.5) | 0;
8615 }
8616 var b = color[2];
8617 if (b != (b | 0)) {
8618 b = (b + 0.5) | 0;
8619 }
8620 var a = color[3] === undefined ? 1 : color[3];
8621 return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
8622};
8623
8624goog.provide('ol.colorlike');
8625
8626goog.require('ol.color');
8627
8628
8629/**
8630 * @param {ol.Color|ol.ColorLike} color Color.
8631 * @return {ol.ColorLike} The color as an ol.ColorLike
8632 * @api
8633 */
8634ol.colorlike.asColorLike = function(color) {
8635 if (ol.colorlike.isColorLike(color)) {
8636 return /** @type {string|CanvasPattern|CanvasGradient} */ (color);
8637 } else {
8638 return ol.color.asString(/** @type {ol.Color} */ (color));
8639 }
8640};
8641
8642
8643/**
8644 * @param {?} color The value that is potentially an ol.ColorLike
8645 * @return {boolean} Whether the color is an ol.ColorLike
8646 */
8647ol.colorlike.isColorLike = function(color) {
8648 return (
8649 typeof color === 'string' ||
8650 color instanceof CanvasPattern ||
8651 color instanceof CanvasGradient
8652 );
8653};
8654
8655goog.provide('ol.dom');
8656
8657
8658/**
8659 * Create an html canvas element and returns its 2d context.
8660 * @param {number=} opt_width Canvas width.
8661 * @param {number=} opt_height Canvas height.
8662 * @return {CanvasRenderingContext2D} The context.
8663 */
8664ol.dom.createCanvasContext2D = function(opt_width, opt_height) {
8665 var canvas = document.createElement('CANVAS');
8666 if (opt_width) {
8667 canvas.width = opt_width;
8668 }
8669 if (opt_height) {
8670 canvas.height = opt_height;
8671 }
8672 return canvas.getContext('2d');
8673};
8674
8675
8676/**
8677 * Get the current computed width for the given element including margin,
8678 * padding and border.
8679 * Equivalent to jQuery's `$(el).outerWidth(true)`.
8680 * @param {!Element} element Element.
8681 * @return {number} The width.
8682 */
8683ol.dom.outerWidth = function(element) {
8684 var width = element.offsetWidth;
8685 var style = getComputedStyle(element);
8686 width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
8687
8688 return width;
8689};
8690
8691
8692/**
8693 * Get the current computed height for the given element including margin,
8694 * padding and border.
8695 * Equivalent to jQuery's `$(el).outerHeight(true)`.
8696 * @param {!Element} element Element.
8697 * @return {number} The height.
8698 */
8699ol.dom.outerHeight = function(element) {
8700 var height = element.offsetHeight;
8701 var style = getComputedStyle(element);
8702 height += parseInt(style.marginTop, 10) + parseInt(style.marginBottom, 10);
8703
8704 return height;
8705};
8706
8707/**
8708 * @param {Node} newNode Node to replace old node
8709 * @param {Node} oldNode The node to be replaced
8710 */
8711ol.dom.replaceNode = function(newNode, oldNode) {
8712 var parent = oldNode.parentNode;
8713 if (parent) {
8714 parent.replaceChild(newNode, oldNode);
8715 }
8716};
8717
8718/**
8719 * @param {Node} node The node to remove.
8720 * @returns {Node} The node that was removed or null.
8721 */
8722ol.dom.removeNode = function(node) {
8723 return node && node.parentNode ? node.parentNode.removeChild(node) : null;
8724};
8725
8726/**
8727 * @param {Node} node The node to remove the children from.
8728 */
8729ol.dom.removeChildren = function(node) {
8730 while (node.lastChild) {
8731 node.removeChild(node.lastChild);
8732 }
8733};
8734
8735goog.provide('ol.MapEventType');
8736
8737/**
8738 * @enum {string}
8739 */
8740ol.MapEventType = {
8741
8742 /**
8743 * Triggered after a map frame is rendered.
8744 * @event ol.MapEvent#postrender
8745 * @api
8746 */
8747 POSTRENDER: 'postrender',
8748
8749 /**
8750 * Triggered when the map starts moving.
8751 * @event ol.MapEvent#movestart
8752 * @api
8753 */
8754 MOVESTART: 'movestart',
8755
8756 /**
8757 * Triggered after the map is moved.
8758 * @event ol.MapEvent#moveend
8759 * @api
8760 */
8761 MOVEEND: 'moveend'
8762
8763};
8764
8765goog.provide('ol.control.Control');
8766
8767goog.require('ol');
8768goog.require('ol.MapEventType');
8769goog.require('ol.Object');
8770goog.require('ol.dom');
8771goog.require('ol.events');
8772
8773
8774/**
8775 * @classdesc
8776 * A control is a visible widget with a DOM element in a fixed position on the
8777 * screen. They can involve user input (buttons), or be informational only;
8778 * the position is determined using CSS. By default these are placed in the
8779 * container with CSS class name `ol-overlaycontainer-stopevent`, but can use
8780 * any outside DOM element.
8781 *
8782 * This is the base class for controls. You can use it for simple custom
8783 * controls by creating the element with listeners, creating an instance:
8784 * ```js
8785 * var myControl = new ol.control.Control({element: myElement});
8786 * ```
8787 * and then adding this to the map.
8788 *
8789 * The main advantage of having this as a control rather than a simple separate
8790 * DOM element is that preventing propagation is handled for you. Controls
8791 * will also be `ol.Object`s in a `ol.Collection`, so you can use their
8792 * methods.
8793 *
8794 * You can also extend this base for your own control class. See
8795 * examples/custom-controls for an example of how to do this.
8796 *
8797 * @constructor
8798 * @extends {ol.Object}
8799 * @implements {oli.control.Control}
8800 * @param {olx.control.ControlOptions} options Control options.
8801 * @api
8802 */
8803ol.control.Control = function(options) {
8804
8805 ol.Object.call(this);
8806
8807 /**
8808 * @protected
8809 * @type {Element}
8810 */
8811 this.element = options.element ? options.element : null;
8812
8813 /**
8814 * @private
8815 * @type {Element}
8816 */
8817 this.target_ = null;
8818
8819 /**
8820 * @private
8821 * @type {ol.Map}
8822 */
8823 this.map_ = null;
8824
8825 /**
8826 * @protected
8827 * @type {!Array.<ol.EventsKey>}
8828 */
8829 this.listenerKeys = [];
8830
8831 /**
8832 * @type {function(ol.MapEvent)}
8833 */
8834 this.render = options.render ? options.render : ol.nullFunction;
8835
8836 if (options.target) {
8837 this.setTarget(options.target);
8838 }
8839
8840};
8841ol.inherits(ol.control.Control, ol.Object);
8842
8843
8844/**
8845 * @inheritDoc
8846 */
8847ol.control.Control.prototype.disposeInternal = function() {
8848 ol.dom.removeNode(this.element);
8849 ol.Object.prototype.disposeInternal.call(this);
8850};
8851
8852
8853/**
8854 * Get the map associated with this control.
8855 * @return {ol.Map} Map.
8856 * @api
8857 */
8858ol.control.Control.prototype.getMap = function() {
8859 return this.map_;
8860};
8861
8862
8863/**
8864 * Remove the control from its current map and attach it to the new map.
8865 * Subclasses may set up event handlers to get notified about changes to
8866 * the map here.
8867 * @param {ol.Map} map Map.
8868 * @override
8869 * @api
8870 */
8871ol.control.Control.prototype.setMap = function(map) {
8872 if (this.map_) {
8873 ol.dom.removeNode(this.element);
8874 }
8875 for (var i = 0, ii = this.listenerKeys.length; i < ii; ++i) {
8876 ol.events.unlistenByKey(this.listenerKeys[i]);
8877 }
8878 this.listenerKeys.length = 0;
8879 this.map_ = map;
8880 if (this.map_) {
8881 var target = this.target_ ?
8882 this.target_ : map.getOverlayContainerStopEvent();
8883 target.appendChild(this.element);
8884 if (this.render !== ol.nullFunction) {
8885 this.listenerKeys.push(ol.events.listen(map,
8886 ol.MapEventType.POSTRENDER, this.render, this));
8887 }
8888 map.render();
8889 }
8890};
8891
8892
8893/**
8894 * This function is used to set a target element for the control. It has no
8895 * effect if it is called after the control has been added to the map (i.e.
8896 * after `setMap` is called on the control). If no `target` is set in the
8897 * options passed to the control constructor and if `setTarget` is not called
8898 * then the control is added to the map's overlay container.
8899 * @param {Element|string} target Target.
8900 * @api
8901 */
8902ol.control.Control.prototype.setTarget = function(target) {
8903 this.target_ = typeof target === 'string' ?
8904 document.getElementById(target) :
8905 target;
8906};
8907
8908goog.provide('ol.css');
8909
8910
8911/**
8912 * The CSS class for hidden feature.
8913 *
8914 * @const
8915 * @type {string}
8916 */
8917ol.css.CLASS_HIDDEN = 'ol-hidden';
8918
8919
8920/**
8921 * The CSS class that we'll give the DOM elements to have them selectable.
8922 *
8923 * @const
8924 * @type {string}
8925 */
8926ol.css.CLASS_SELECTABLE = 'ol-selectable';
8927
8928/**
8929 * The CSS class that we'll give the DOM elements to have them unselectable.
8930 *
8931 * @const
8932 * @type {string}
8933 */
8934ol.css.CLASS_UNSELECTABLE = 'ol-unselectable';
8935
8936
8937/**
8938 * The CSS class for unsupported feature.
8939 *
8940 * @const
8941 * @type {string}
8942 */
8943ol.css.CLASS_UNSUPPORTED = 'ol-unsupported';
8944
8945
8946/**
8947 * The CSS class for controls.
8948 *
8949 * @const
8950 * @type {string}
8951 */
8952ol.css.CLASS_CONTROL = 'ol-control';
8953
8954// FIXME handle date line wrap
8955
8956goog.provide('ol.control.Attribution');
8957
8958goog.require('ol');
8959goog.require('ol.dom');
8960goog.require('ol.control.Control');
8961goog.require('ol.css');
8962goog.require('ol.events');
8963goog.require('ol.events.EventType');
8964goog.require('ol.obj');
8965
8966
8967/**
8968 * @classdesc
8969 * Control to show all the attributions associated with the layer sources
8970 * in the map. This control is one of the default controls included in maps.
8971 * By default it will show in the bottom right portion of the map, but this can
8972 * be changed by using a css selector for `.ol-attribution`.
8973 *
8974 * @constructor
8975 * @extends {ol.control.Control}
8976 * @param {olx.control.AttributionOptions=} opt_options Attribution options.
8977 * @api
8978 */
8979ol.control.Attribution = function(opt_options) {
8980
8981 var options = opt_options ? opt_options : {};
8982
8983 /**
8984 * @private
8985 * @type {Element}
8986 */
8987 this.ulElement_ = document.createElement('UL');
8988
8989 /**
8990 * @private
8991 * @type {Element}
8992 */
8993 this.logoLi_ = document.createElement('LI');
8994
8995 this.ulElement_.appendChild(this.logoLi_);
8996 this.logoLi_.style.display = 'none';
8997
8998 /**
8999 * @private
9000 * @type {boolean}
9001 */
9002 this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
9003
9004 /**
9005 * @private
9006 * @type {boolean}
9007 */
9008 this.collapsible_ = options.collapsible !== undefined ?
9009 options.collapsible : true;
9010
9011 if (!this.collapsible_) {
9012 this.collapsed_ = false;
9013 }
9014
9015 var className = options.className !== undefined ? options.className : 'ol-attribution';
9016
9017 var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Attributions';
9018
9019 var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00BB';
9020
9021 if (typeof collapseLabel === 'string') {
9022 /**
9023 * @private
9024 * @type {Node}
9025 */
9026 this.collapseLabel_ = document.createElement('span');
9027 this.collapseLabel_.textContent = collapseLabel;
9028 } else {
9029 this.collapseLabel_ = collapseLabel;
9030 }
9031
9032 var label = options.label !== undefined ? options.label : 'i';
9033
9034 if (typeof label === 'string') {
9035 /**
9036 * @private
9037 * @type {Node}
9038 */
9039 this.label_ = document.createElement('span');
9040 this.label_.textContent = label;
9041 } else {
9042 this.label_ = label;
9043 }
9044
9045
9046 var activeLabel = (this.collapsible_ && !this.collapsed_) ?
9047 this.collapseLabel_ : this.label_;
9048 var button = document.createElement('button');
9049 button.setAttribute('type', 'button');
9050 button.title = tipLabel;
9051 button.appendChild(activeLabel);
9052
9053 ol.events.listen(button, ol.events.EventType.CLICK, this.handleClick_, this);
9054
9055 var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
9056 ol.css.CLASS_CONTROL +
9057 (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
9058 (this.collapsible_ ? '' : ' ol-uncollapsible');
9059 var element = document.createElement('div');
9060 element.className = cssClasses;
9061 element.appendChild(this.ulElement_);
9062 element.appendChild(button);
9063
9064 var render = options.render ? options.render : ol.control.Attribution.render;
9065
9066 ol.control.Control.call(this, {
9067 element: element,
9068 render: render,
9069 target: options.target
9070 });
9071
9072 /**
9073 * @private
9074 * @type {boolean}
9075 */
9076 this.renderedVisible_ = true;
9077
9078 /**
9079 * @private
9080 * @type {Object.<string, Element>}
9081 */
9082 this.attributionElements_ = {};
9083
9084 /**
9085 * @private
9086 * @type {Object.<string, boolean>}
9087 */
9088 this.attributionElementRenderedVisible_ = {};
9089
9090 /**
9091 * @private
9092 * @type {Object.<string, Element>}
9093 */
9094 this.logoElements_ = {};
9095
9096};
9097ol.inherits(ol.control.Attribution, ol.control.Control);
9098
9099
9100/**
9101 * @param {?olx.FrameState} frameState Frame state.
9102 * @return {Array.<Object.<string, ol.Attribution>>} Attributions.
9103 */
9104ol.control.Attribution.prototype.getSourceAttributions = function(frameState) {
9105 var i, ii, j, jj, tileRanges, source, sourceAttribution,
9106 sourceAttributionKey, sourceAttributions, sourceKey;
9107 var intersectsTileRange;
9108 var layerStatesArray = frameState.layerStatesArray;
9109 /** @type {Object.<string, ol.Attribution>} */
9110 var attributions = ol.obj.assign({}, frameState.attributions);
9111 /** @type {Object.<string, ol.Attribution>} */
9112 var hiddenAttributions = {};
9113 var uniqueAttributions = {};
9114 var projection = /** @type {!ol.proj.Projection} */ (frameState.viewState.projection);
9115 for (i = 0, ii = layerStatesArray.length; i < ii; i++) {
9116 source = layerStatesArray[i].layer.getSource();
9117 if (!source) {
9118 continue;
9119 }
9120 sourceKey = ol.getUid(source).toString();
9121 sourceAttributions = source.getAttributions();
9122 if (!sourceAttributions) {
9123 continue;
9124 }
9125 for (j = 0, jj = sourceAttributions.length; j < jj; j++) {
9126 sourceAttribution = sourceAttributions[j];
9127 sourceAttributionKey = ol.getUid(sourceAttribution).toString();
9128 if (sourceAttributionKey in attributions) {
9129 continue;
9130 }
9131 tileRanges = frameState.usedTiles[sourceKey];
9132 if (tileRanges) {
9133 var tileGrid = /** @type {ol.source.Tile} */ (source).getTileGridForProjection(projection);
9134 intersectsTileRange = sourceAttribution.intersectsAnyTileRange(
9135 tileRanges, tileGrid, projection);
9136 } else {
9137 intersectsTileRange = false;
9138 }
9139 if (intersectsTileRange) {
9140 if (sourceAttributionKey in hiddenAttributions) {
9141 delete hiddenAttributions[sourceAttributionKey];
9142 }
9143 var html = sourceAttribution.getHTML();
9144 if (!(html in uniqueAttributions)) {
9145 uniqueAttributions[html] = true;
9146 attributions[sourceAttributionKey] = sourceAttribution;
9147 }
9148 } else {
9149 hiddenAttributions[sourceAttributionKey] = sourceAttribution;
9150 }
9151 }
9152 }
9153 return [attributions, hiddenAttributions];
9154};
9155
9156
9157/**
9158 * Update the attribution element.
9159 * @param {ol.MapEvent} mapEvent Map event.
9160 * @this {ol.control.Attribution}
9161 * @api
9162 */
9163ol.control.Attribution.render = function(mapEvent) {
9164 this.updateElement_(mapEvent.frameState);
9165};
9166
9167
9168/**
9169 * @private
9170 * @param {?olx.FrameState} frameState Frame state.
9171 */
9172ol.control.Attribution.prototype.updateElement_ = function(frameState) {
9173
9174 if (!frameState) {
9175 if (this.renderedVisible_) {
9176 this.element.style.display = 'none';
9177 this.renderedVisible_ = false;
9178 }
9179 return;
9180 }
9181
9182 var attributions = this.getSourceAttributions(frameState);
9183 /** @type {Object.<string, ol.Attribution>} */
9184 var visibleAttributions = attributions[0];
9185 /** @type {Object.<string, ol.Attribution>} */
9186 var hiddenAttributions = attributions[1];
9187
9188 var attributionElement, attributionKey;
9189 for (attributionKey in this.attributionElements_) {
9190 if (attributionKey in visibleAttributions) {
9191 if (!this.attributionElementRenderedVisible_[attributionKey]) {
9192 this.attributionElements_[attributionKey].style.display = '';
9193 this.attributionElementRenderedVisible_[attributionKey] = true;
9194 }
9195 delete visibleAttributions[attributionKey];
9196 } else if (attributionKey in hiddenAttributions) {
9197 if (this.attributionElementRenderedVisible_[attributionKey]) {
9198 this.attributionElements_[attributionKey].style.display = 'none';
9199 delete this.attributionElementRenderedVisible_[attributionKey];
9200 }
9201 delete hiddenAttributions[attributionKey];
9202 } else {
9203 ol.dom.removeNode(this.attributionElements_[attributionKey]);
9204 delete this.attributionElements_[attributionKey];
9205 delete this.attributionElementRenderedVisible_[attributionKey];
9206 }
9207 }
9208 for (attributionKey in visibleAttributions) {
9209 attributionElement = document.createElement('LI');
9210 attributionElement.innerHTML =
9211 visibleAttributions[attributionKey].getHTML();
9212 this.ulElement_.appendChild(attributionElement);
9213 this.attributionElements_[attributionKey] = attributionElement;
9214 this.attributionElementRenderedVisible_[attributionKey] = true;
9215 }
9216 for (attributionKey in hiddenAttributions) {
9217 attributionElement = document.createElement('LI');
9218 attributionElement.innerHTML =
9219 hiddenAttributions[attributionKey].getHTML();
9220 attributionElement.style.display = 'none';
9221 this.ulElement_.appendChild(attributionElement);
9222 this.attributionElements_[attributionKey] = attributionElement;
9223 }
9224
9225 var renderVisible =
9226 !ol.obj.isEmpty(this.attributionElementRenderedVisible_) ||
9227 !ol.obj.isEmpty(frameState.logos);
9228 if (this.renderedVisible_ != renderVisible) {
9229 this.element.style.display = renderVisible ? '' : 'none';
9230 this.renderedVisible_ = renderVisible;
9231 }
9232 if (renderVisible &&
9233 ol.obj.isEmpty(this.attributionElementRenderedVisible_)) {
9234 this.element.classList.add('ol-logo-only');
9235 } else {
9236 this.element.classList.remove('ol-logo-only');
9237 }
9238
9239 this.insertLogos_(frameState);
9240
9241};
9242
9243
9244/**
9245 * @param {?olx.FrameState} frameState Frame state.
9246 * @private
9247 */
9248ol.control.Attribution.prototype.insertLogos_ = function(frameState) {
9249
9250 var logo;
9251 var logos = frameState.logos;
9252 var logoElements = this.logoElements_;
9253
9254 for (logo in logoElements) {
9255 if (!(logo in logos)) {
9256 ol.dom.removeNode(logoElements[logo]);
9257 delete logoElements[logo];
9258 }
9259 }
9260
9261 var image, logoElement, logoKey;
9262 for (logoKey in logos) {
9263 var logoValue = logos[logoKey];
9264 if (logoValue instanceof HTMLElement) {
9265 this.logoLi_.appendChild(logoValue);
9266 logoElements[logoKey] = logoValue;
9267 }
9268 if (!(logoKey in logoElements)) {
9269 image = new Image();
9270 image.src = logoKey;
9271 if (logoValue === '') {
9272 logoElement = image;
9273 } else {
9274 logoElement = document.createElement('a');
9275 logoElement.href = logoValue;
9276 logoElement.appendChild(image);
9277 }
9278 this.logoLi_.appendChild(logoElement);
9279 logoElements[logoKey] = logoElement;
9280 }
9281 }
9282
9283 this.logoLi_.style.display = !ol.obj.isEmpty(logos) ? '' : 'none';
9284
9285};
9286
9287
9288/**
9289 * @param {Event} event The event to handle
9290 * @private
9291 */
9292ol.control.Attribution.prototype.handleClick_ = function(event) {
9293 event.preventDefault();
9294 this.handleToggle_();
9295};
9296
9297
9298/**
9299 * @private
9300 */
9301ol.control.Attribution.prototype.handleToggle_ = function() {
9302 this.element.classList.toggle('ol-collapsed');
9303 if (this.collapsed_) {
9304 ol.dom.replaceNode(this.collapseLabel_, this.label_);
9305 } else {
9306 ol.dom.replaceNode(this.label_, this.collapseLabel_);
9307 }
9308 this.collapsed_ = !this.collapsed_;
9309};
9310
9311
9312/**
9313 * Return `true` if the attribution is collapsible, `false` otherwise.
9314 * @return {boolean} True if the widget is collapsible.
9315 * @api
9316 */
9317ol.control.Attribution.prototype.getCollapsible = function() {
9318 return this.collapsible_;
9319};
9320
9321
9322/**
9323 * Set whether the attribution should be collapsible.
9324 * @param {boolean} collapsible True if the widget is collapsible.
9325 * @api
9326 */
9327ol.control.Attribution.prototype.setCollapsible = function(collapsible) {
9328 if (this.collapsible_ === collapsible) {
9329 return;
9330 }
9331 this.collapsible_ = collapsible;
9332 this.element.classList.toggle('ol-uncollapsible');
9333 if (!collapsible && this.collapsed_) {
9334 this.handleToggle_();
9335 }
9336};
9337
9338
9339/**
9340 * Collapse or expand the attribution according to the passed parameter. Will
9341 * not do anything if the attribution isn't collapsible or if the current
9342 * collapsed state is already the one requested.
9343 * @param {boolean} collapsed True if the widget is collapsed.
9344 * @api
9345 */
9346ol.control.Attribution.prototype.setCollapsed = function(collapsed) {
9347 if (!this.collapsible_ || this.collapsed_ === collapsed) {
9348 return;
9349 }
9350 this.handleToggle_();
9351};
9352
9353
9354/**
9355 * Return `true` when the attribution is currently collapsed or `false`
9356 * otherwise.
9357 * @return {boolean} True if the widget is collapsed.
9358 * @api
9359 */
9360ol.control.Attribution.prototype.getCollapsed = function() {
9361 return this.collapsed_;
9362};
9363
9364goog.provide('ol.easing');
9365
9366
9367/**
9368 * Start slow and speed up.
9369 * @param {number} t Input between 0 and 1.
9370 * @return {number} Output between 0 and 1.
9371 * @api
9372 */
9373ol.easing.easeIn = function(t) {
9374 return Math.pow(t, 3);
9375};
9376
9377
9378/**
9379 * Start fast and slow down.
9380 * @param {number} t Input between 0 and 1.
9381 * @return {number} Output between 0 and 1.
9382 * @api
9383 */
9384ol.easing.easeOut = function(t) {
9385 return 1 - ol.easing.easeIn(1 - t);
9386};
9387
9388
9389/**
9390 * Start slow, speed up, and then slow down again.
9391 * @param {number} t Input between 0 and 1.
9392 * @return {number} Output between 0 and 1.
9393 * @api
9394 */
9395ol.easing.inAndOut = function(t) {
9396 return 3 * t * t - 2 * t * t * t;
9397};
9398
9399
9400/**
9401 * Maintain a constant speed over time.
9402 * @param {number} t Input between 0 and 1.
9403 * @return {number} Output between 0 and 1.
9404 * @api
9405 */
9406ol.easing.linear = function(t) {
9407 return t;
9408};
9409
9410
9411/**
9412 * Start slow, speed up, and at the very end slow down again. This has the
9413 * same general behavior as {@link ol.easing.inAndOut}, but the final slowdown
9414 * is delayed.
9415 * @param {number} t Input between 0 and 1.
9416 * @return {number} Output between 0 and 1.
9417 * @api
9418 */
9419ol.easing.upAndDown = function(t) {
9420 if (t < 0.5) {
9421 return ol.easing.inAndOut(2 * t);
9422 } else {
9423 return 1 - ol.easing.inAndOut(2 * (t - 0.5));
9424 }
9425};
9426
9427goog.provide('ol.control.Rotate');
9428
9429goog.require('ol.events');
9430goog.require('ol.events.EventType');
9431goog.require('ol');
9432goog.require('ol.control.Control');
9433goog.require('ol.css');
9434goog.require('ol.easing');
9435
9436
9437/**
9438 * @classdesc
9439 * A button control to reset rotation to 0.
9440 * To style this control use css selector `.ol-rotate`. A `.ol-hidden` css
9441 * selector is added to the button when the rotation is 0.
9442 *
9443 * @constructor
9444 * @extends {ol.control.Control}
9445 * @param {olx.control.RotateOptions=} opt_options Rotate options.
9446 * @api
9447 */
9448ol.control.Rotate = function(opt_options) {
9449
9450 var options = opt_options ? opt_options : {};
9451
9452 var className = options.className !== undefined ? options.className : 'ol-rotate';
9453
9454 var label = options.label !== undefined ? options.label : '\u21E7';
9455
9456 /**
9457 * @type {Element}
9458 * @private
9459 */
9460 this.label_ = null;
9461
9462 if (typeof label === 'string') {
9463 this.label_ = document.createElement('span');
9464 this.label_.className = 'ol-compass';
9465 this.label_.textContent = label;
9466 } else {
9467 this.label_ = label;
9468 this.label_.classList.add('ol-compass');
9469 }
9470
9471 var tipLabel = options.tipLabel ? options.tipLabel : 'Reset rotation';
9472
9473 var button = document.createElement('button');
9474 button.className = className + '-reset';
9475 button.setAttribute('type', 'button');
9476 button.title = tipLabel;
9477 button.appendChild(this.label_);
9478
9479 ol.events.listen(button, ol.events.EventType.CLICK,
9480 ol.control.Rotate.prototype.handleClick_, this);
9481
9482 var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
9483 ol.css.CLASS_CONTROL;
9484 var element = document.createElement('div');
9485 element.className = cssClasses;
9486 element.appendChild(button);
9487
9488 var render = options.render ? options.render : ol.control.Rotate.render;
9489
9490 this.callResetNorth_ = options.resetNorth ? options.resetNorth : undefined;
9491
9492 ol.control.Control.call(this, {
9493 element: element,
9494 render: render,
9495 target: options.target
9496 });
9497
9498 /**
9499 * @type {number}
9500 * @private
9501 */
9502 this.duration_ = options.duration !== undefined ? options.duration : 250;
9503
9504 /**
9505 * @type {boolean}
9506 * @private
9507 */
9508 this.autoHide_ = options.autoHide !== undefined ? options.autoHide : true;
9509
9510 /**
9511 * @private
9512 * @type {number|undefined}
9513 */
9514 this.rotation_ = undefined;
9515
9516 if (this.autoHide_) {
9517 this.element.classList.add(ol.css.CLASS_HIDDEN);
9518 }
9519
9520};
9521ol.inherits(ol.control.Rotate, ol.control.Control);
9522
9523
9524/**
9525 * @param {Event} event The event to handle
9526 * @private
9527 */
9528ol.control.Rotate.prototype.handleClick_ = function(event) {
9529 event.preventDefault();
9530 if (this.callResetNorth_ !== undefined) {
9531 this.callResetNorth_();
9532 } else {
9533 this.resetNorth_();
9534 }
9535};
9536
9537
9538/**
9539 * @private
9540 */
9541ol.control.Rotate.prototype.resetNorth_ = function() {
9542 var map = this.getMap();
9543 var view = map.getView();
9544 if (!view) {
9545 // the map does not have a view, so we can't act
9546 // upon it
9547 return;
9548 }
9549 if (view.getRotation() !== undefined) {
9550 if (this.duration_ > 0) {
9551 view.animate({
9552 rotation: 0,
9553 duration: this.duration_,
9554 easing: ol.easing.easeOut
9555 });
9556 } else {
9557 view.setRotation(0);
9558 }
9559 }
9560};
9561
9562
9563/**
9564 * Update the rotate control element.
9565 * @param {ol.MapEvent} mapEvent Map event.
9566 * @this {ol.control.Rotate}
9567 * @api
9568 */
9569ol.control.Rotate.render = function(mapEvent) {
9570 var frameState = mapEvent.frameState;
9571 if (!frameState) {
9572 return;
9573 }
9574 var rotation = frameState.viewState.rotation;
9575 if (rotation != this.rotation_) {
9576 var transform = 'rotate(' + rotation + 'rad)';
9577 if (this.autoHide_) {
9578 var contains = this.element.classList.contains(ol.css.CLASS_HIDDEN);
9579 if (!contains && rotation === 0) {
9580 this.element.classList.add(ol.css.CLASS_HIDDEN);
9581 } else if (contains && rotation !== 0) {
9582 this.element.classList.remove(ol.css.CLASS_HIDDEN);
9583 }
9584 }
9585 this.label_.style.msTransform = transform;
9586 this.label_.style.webkitTransform = transform;
9587 this.label_.style.transform = transform;
9588 }
9589 this.rotation_ = rotation;
9590};
9591
9592goog.provide('ol.control.Zoom');
9593
9594goog.require('ol');
9595goog.require('ol.events');
9596goog.require('ol.events.EventType');
9597goog.require('ol.control.Control');
9598goog.require('ol.css');
9599goog.require('ol.easing');
9600
9601
9602/**
9603 * @classdesc
9604 * A control with 2 buttons, one for zoom in and one for zoom out.
9605 * This control is one of the default controls of a map. To style this control
9606 * use css selectors `.ol-zoom-in` and `.ol-zoom-out`.
9607 *
9608 * @constructor
9609 * @extends {ol.control.Control}
9610 * @param {olx.control.ZoomOptions=} opt_options Zoom options.
9611 * @api
9612 */
9613ol.control.Zoom = function(opt_options) {
9614
9615 var options = opt_options ? opt_options : {};
9616
9617 var className = options.className !== undefined ? options.className : 'ol-zoom';
9618
9619 var delta = options.delta !== undefined ? options.delta : 1;
9620
9621 var zoomInLabel = options.zoomInLabel !== undefined ? options.zoomInLabel : '+';
9622 var zoomOutLabel = options.zoomOutLabel !== undefined ? options.zoomOutLabel : '\u2212';
9623
9624 var zoomInTipLabel = options.zoomInTipLabel !== undefined ?
9625 options.zoomInTipLabel : 'Zoom in';
9626 var zoomOutTipLabel = options.zoomOutTipLabel !== undefined ?
9627 options.zoomOutTipLabel : 'Zoom out';
9628
9629 var inElement = document.createElement('button');
9630 inElement.className = className + '-in';
9631 inElement.setAttribute('type', 'button');
9632 inElement.title = zoomInTipLabel;
9633 inElement.appendChild(
9634 typeof zoomInLabel === 'string' ? document.createTextNode(zoomInLabel) : zoomInLabel
9635 );
9636
9637 ol.events.listen(inElement, ol.events.EventType.CLICK,
9638 ol.control.Zoom.prototype.handleClick_.bind(this, delta));
9639
9640 var outElement = document.createElement('button');
9641 outElement.className = className + '-out';
9642 outElement.setAttribute('type', 'button');
9643 outElement.title = zoomOutTipLabel;
9644 outElement.appendChild(
9645 typeof zoomOutLabel === 'string' ? document.createTextNode(zoomOutLabel) : zoomOutLabel
9646 );
9647
9648 ol.events.listen(outElement, ol.events.EventType.CLICK,
9649 ol.control.Zoom.prototype.handleClick_.bind(this, -delta));
9650
9651 var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
9652 ol.css.CLASS_CONTROL;
9653 var element = document.createElement('div');
9654 element.className = cssClasses;
9655 element.appendChild(inElement);
9656 element.appendChild(outElement);
9657
9658 ol.control.Control.call(this, {
9659 element: element,
9660 target: options.target
9661 });
9662
9663 /**
9664 * @type {number}
9665 * @private
9666 */
9667 this.duration_ = options.duration !== undefined ? options.duration : 250;
9668
9669};
9670ol.inherits(ol.control.Zoom, ol.control.Control);
9671
9672
9673/**
9674 * @param {number} delta Zoom delta.
9675 * @param {Event} event The event to handle
9676 * @private
9677 */
9678ol.control.Zoom.prototype.handleClick_ = function(delta, event) {
9679 event.preventDefault();
9680 this.zoomByDelta_(delta);
9681};
9682
9683
9684/**
9685 * @param {number} delta Zoom delta.
9686 * @private
9687 */
9688ol.control.Zoom.prototype.zoomByDelta_ = function(delta) {
9689 var map = this.getMap();
9690 var view = map.getView();
9691 if (!view) {
9692 // the map does not have a view, so we can't act
9693 // upon it
9694 return;
9695 }
9696 var currentResolution = view.getResolution();
9697 if (currentResolution) {
9698 var newResolution = view.constrainResolution(currentResolution, delta);
9699 if (this.duration_ > 0) {
9700 if (view.getAnimating()) {
9701 view.cancelAnimations();
9702 }
9703 view.animate({
9704 resolution: newResolution,
9705 duration: this.duration_,
9706 easing: ol.easing.easeOut
9707 });
9708 } else {
9709 view.setResolution(newResolution);
9710 }
9711 }
9712};
9713
9714goog.provide('ol.control');
9715
9716goog.require('ol.Collection');
9717goog.require('ol.control.Attribution');
9718goog.require('ol.control.Rotate');
9719goog.require('ol.control.Zoom');
9720
9721
9722/**
9723 * Set of controls included in maps by default. Unless configured otherwise,
9724 * this returns a collection containing an instance of each of the following
9725 * controls:
9726 * * {@link ol.control.Zoom}
9727 * * {@link ol.control.Rotate}
9728 * * {@link ol.control.Attribution}
9729 *
9730 * @param {olx.control.DefaultsOptions=} opt_options Defaults options.
9731 * @return {ol.Collection.<ol.control.Control>} Controls.
9732 * @api
9733 */
9734ol.control.defaults = function(opt_options) {
9735
9736 var options = opt_options ? opt_options : {};
9737
9738 var controls = new ol.Collection();
9739
9740 var zoomControl = options.zoom !== undefined ? options.zoom : true;
9741 if (zoomControl) {
9742 controls.push(new ol.control.Zoom(options.zoomOptions));
9743 }
9744
9745 var rotateControl = options.rotate !== undefined ? options.rotate : true;
9746 if (rotateControl) {
9747 controls.push(new ol.control.Rotate(options.rotateOptions));
9748 }
9749
9750 var attributionControl = options.attribution !== undefined ?
9751 options.attribution : true;
9752 if (attributionControl) {
9753 controls.push(new ol.control.Attribution(options.attributionOptions));
9754 }
9755
9756 return controls;
9757
9758};
9759
9760goog.provide('ol.control.FullScreen');
9761
9762goog.require('ol');
9763goog.require('ol.control.Control');
9764goog.require('ol.css');
9765goog.require('ol.dom');
9766goog.require('ol.events');
9767goog.require('ol.events.EventType');
9768
9769
9770/**
9771 * @classdesc
9772 * Provides a button that when clicked fills up the full screen with the map.
9773 * The full screen source element is by default the element containing the map viewport unless
9774 * overridden by providing the `source` option. In which case, the dom
9775 * element introduced using this parameter will be displayed in full screen.
9776 *
9777 * When in full screen mode, a close button is shown to exit full screen mode.
9778 * The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
9779 * toggle the map in full screen mode.
9780 *
9781 *
9782 * @constructor
9783 * @extends {ol.control.Control}
9784 * @param {olx.control.FullScreenOptions=} opt_options Options.
9785 * @api
9786 */
9787ol.control.FullScreen = function(opt_options) {
9788
9789 var options = opt_options ? opt_options : {};
9790
9791 /**
9792 * @private
9793 * @type {string}
9794 */
9795 this.cssClassName_ = options.className !== undefined ? options.className :
9796 'ol-full-screen';
9797
9798 var label = options.label !== undefined ? options.label : '\u2922';
9799
9800 /**
9801 * @private
9802 * @type {Node}
9803 */
9804 this.labelNode_ = typeof label === 'string' ?
9805 document.createTextNode(label) : label;
9806
9807 var labelActive = options.labelActive !== undefined ? options.labelActive : '\u00d7';
9808
9809 /**
9810 * @private
9811 * @type {Node}
9812 */
9813 this.labelActiveNode_ = typeof labelActive === 'string' ?
9814 document.createTextNode(labelActive) : labelActive;
9815
9816 var tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
9817 var button = document.createElement('button');
9818 button.className = this.cssClassName_ + '-' + ol.control.FullScreen.isFullScreen();
9819 button.setAttribute('type', 'button');
9820 button.title = tipLabel;
9821 button.appendChild(this.labelNode_);
9822
9823 ol.events.listen(button, ol.events.EventType.CLICK,
9824 this.handleClick_, this);
9825
9826 var cssClasses = this.cssClassName_ + ' ' + ol.css.CLASS_UNSELECTABLE +
9827 ' ' + ol.css.CLASS_CONTROL + ' ' +
9828 (!ol.control.FullScreen.isFullScreenSupported() ? ol.css.CLASS_UNSUPPORTED : '');
9829 var element = document.createElement('div');
9830 element.className = cssClasses;
9831 element.appendChild(button);
9832
9833 ol.control.Control.call(this, {
9834 element: element,
9835 target: options.target
9836 });
9837
9838 /**
9839 * @private
9840 * @type {boolean}
9841 */
9842 this.keys_ = options.keys !== undefined ? options.keys : false;
9843
9844 /**
9845 * @private
9846 * @type {Element|string|undefined}
9847 */
9848 this.source_ = options.source;
9849
9850};
9851ol.inherits(ol.control.FullScreen, ol.control.Control);
9852
9853
9854/**
9855 * @param {Event} event The event to handle
9856 * @private
9857 */
9858ol.control.FullScreen.prototype.handleClick_ = function(event) {
9859 event.preventDefault();
9860 this.handleFullScreen_();
9861};
9862
9863
9864/**
9865 * @private
9866 */
9867ol.control.FullScreen.prototype.handleFullScreen_ = function() {
9868 if (!ol.control.FullScreen.isFullScreenSupported()) {
9869 return;
9870 }
9871 var map = this.getMap();
9872 if (!map) {
9873 return;
9874 }
9875 if (ol.control.FullScreen.isFullScreen()) {
9876 ol.control.FullScreen.exitFullScreen();
9877 } else {
9878 var element;
9879 if (this.source_) {
9880 element = typeof this.source_ === 'string' ?
9881 document.getElementById(this.source_) :
9882 this.source_;
9883 } else {
9884 element = map.getTargetElement();
9885 }
9886 if (this.keys_) {
9887 ol.control.FullScreen.requestFullScreenWithKeys(element);
9888
9889 } else {
9890 ol.control.FullScreen.requestFullScreen(element);
9891 }
9892 }
9893};
9894
9895
9896/**
9897 * @private
9898 */
9899ol.control.FullScreen.prototype.handleFullScreenChange_ = function() {
9900 var button = this.element.firstElementChild;
9901 var map = this.getMap();
9902 if (ol.control.FullScreen.isFullScreen()) {
9903 button.className = this.cssClassName_ + '-true';
9904 ol.dom.replaceNode(this.labelActiveNode_, this.labelNode_);
9905 } else {
9906 button.className = this.cssClassName_ + '-false';
9907 ol.dom.replaceNode(this.labelNode_, this.labelActiveNode_);
9908 }
9909 if (map) {
9910 map.updateSize();
9911 }
9912};
9913
9914
9915/**
9916 * @inheritDoc
9917 * @api
9918 */
9919ol.control.FullScreen.prototype.setMap = function(map) {
9920 ol.control.Control.prototype.setMap.call(this, map);
9921 if (map) {
9922 this.listenerKeys.push(ol.events.listen(document,
9923 ol.control.FullScreen.getChangeType_(),
9924 this.handleFullScreenChange_, this)
9925 );
9926 }
9927};
9928
9929/**
9930 * @return {boolean} Fullscreen is supported by the current platform.
9931 */
9932ol.control.FullScreen.isFullScreenSupported = function() {
9933 var body = document.body;
9934 return !!(
9935 body.webkitRequestFullscreen ||
9936 (body.mozRequestFullScreen && document.mozFullScreenEnabled) ||
9937 (body.msRequestFullscreen && document.msFullscreenEnabled) ||
9938 (body.requestFullscreen && document.fullscreenEnabled)
9939 );
9940};
9941
9942/**
9943 * @return {boolean} Element is currently in fullscreen.
9944 */
9945ol.control.FullScreen.isFullScreen = function() {
9946 return !!(
9947 document.webkitIsFullScreen || document.mozFullScreen ||
9948 document.msFullscreenElement || document.fullscreenElement
9949 );
9950};
9951
9952/**
9953 * Request to fullscreen an element.
9954 * @param {Node} element Element to request fullscreen
9955 */
9956ol.control.FullScreen.requestFullScreen = function(element) {
9957 if (element.requestFullscreen) {
9958 element.requestFullscreen();
9959 } else if (element.msRequestFullscreen) {
9960 element.msRequestFullscreen();
9961 } else if (element.mozRequestFullScreen) {
9962 element.mozRequestFullScreen();
9963 } else if (element.webkitRequestFullscreen) {
9964 element.webkitRequestFullscreen();
9965 }
9966};
9967
9968/**
9969 * Request to fullscreen an element with keyboard input.
9970 * @param {Node} element Element to request fullscreen
9971 */
9972ol.control.FullScreen.requestFullScreenWithKeys = function(element) {
9973 if (element.mozRequestFullScreenWithKeys) {
9974 element.mozRequestFullScreenWithKeys();
9975 } else if (element.webkitRequestFullscreen) {
9976 element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
9977 } else {
9978 ol.control.FullScreen.requestFullScreen(element);
9979 }
9980};
9981
9982/**
9983 * Exit fullscreen.
9984 */
9985ol.control.FullScreen.exitFullScreen = function() {
9986 if (document.exitFullscreen) {
9987 document.exitFullscreen();
9988 } else if (document.msExitFullscreen) {
9989 document.msExitFullscreen();
9990 } else if (document.mozCancelFullScreen) {
9991 document.mozCancelFullScreen();
9992 } else if (document.webkitExitFullscreen) {
9993 document.webkitExitFullscreen();
9994 }
9995};
9996
9997/**
9998 * @return {string} Change type.
9999 * @private
10000 */
10001ol.control.FullScreen.getChangeType_ = (function() {
10002 var changeType;
10003 return function() {
10004 if (!changeType) {
10005 var body = document.body;
10006 if (body.webkitRequestFullscreen) {
10007 changeType = 'webkitfullscreenchange';
10008 } else if (body.mozRequestFullScreen) {
10009 changeType = 'mozfullscreenchange';
10010 } else if (body.msRequestFullscreen) {
10011 changeType = 'MSFullscreenChange';
10012 } else if (body.requestFullscreen) {
10013 changeType = 'fullscreenchange';
10014 }
10015 }
10016 return changeType;
10017 };
10018})();
10019
10020// FIXME should listen on appropriate pane, once it is defined
10021
10022goog.provide('ol.control.MousePosition');
10023
10024goog.require('ol');
10025goog.require('ol.events');
10026goog.require('ol.events.EventType');
10027goog.require('ol.Object');
10028goog.require('ol.control.Control');
10029goog.require('ol.proj');
10030
10031
10032/**
10033 * @classdesc
10034 * A control to show the 2D coordinates of the mouse cursor. By default, these
10035 * are in the view projection, but can be in any supported projection.
10036 * By default the control is shown in the top right corner of the map, but this
10037 * can be changed by using the css selector `.ol-mouse-position`.
10038 *
10039 * @constructor
10040 * @extends {ol.control.Control}
10041 * @param {olx.control.MousePositionOptions=} opt_options Mouse position
10042 * options.
10043 * @api
10044 */
10045ol.control.MousePosition = function(opt_options) {
10046
10047 var options = opt_options ? opt_options : {};
10048
10049 var element = document.createElement('DIV');
10050 element.className = options.className !== undefined ? options.className : 'ol-mouse-position';
10051
10052 var render = options.render ?
10053 options.render : ol.control.MousePosition.render;
10054
10055 ol.control.Control.call(this, {
10056 element: element,
10057 render: render,
10058 target: options.target
10059 });
10060
10061 ol.events.listen(this,
10062 ol.Object.getChangeEventType(ol.control.MousePosition.Property_.PROJECTION),
10063 this.handleProjectionChanged_, this);
10064
10065 if (options.coordinateFormat) {
10066 this.setCoordinateFormat(options.coordinateFormat);
10067 }
10068 if (options.projection) {
10069 this.setProjection(options.projection);
10070 }
10071
10072 /**
10073 * @private
10074 * @type {string}
10075 */
10076 this.undefinedHTML_ = options.undefinedHTML !== undefined ? options.undefinedHTML : '';
10077
10078 /**
10079 * @private
10080 * @type {string}
10081 */
10082 this.renderedHTML_ = element.innerHTML;
10083
10084 /**
10085 * @private
10086 * @type {ol.proj.Projection}
10087 */
10088 this.mapProjection_ = null;
10089
10090 /**
10091 * @private
10092 * @type {?ol.TransformFunction}
10093 */
10094 this.transform_ = null;
10095
10096 /**
10097 * @private
10098 * @type {ol.Pixel}
10099 */
10100 this.lastMouseMovePixel_ = null;
10101
10102};
10103ol.inherits(ol.control.MousePosition, ol.control.Control);
10104
10105
10106/**
10107 * Update the mouseposition element.
10108 * @param {ol.MapEvent} mapEvent Map event.
10109 * @this {ol.control.MousePosition}
10110 * @api
10111 */
10112ol.control.MousePosition.render = function(mapEvent) {
10113 var frameState = mapEvent.frameState;
10114 if (!frameState) {
10115 this.mapProjection_ = null;
10116 } else {
10117 if (this.mapProjection_ != frameState.viewState.projection) {
10118 this.mapProjection_ = frameState.viewState.projection;
10119 this.transform_ = null;
10120 }
10121 }
10122 this.updateHTML_(this.lastMouseMovePixel_);
10123};
10124
10125
10126/**
10127 * @private
10128 */
10129ol.control.MousePosition.prototype.handleProjectionChanged_ = function() {
10130 this.transform_ = null;
10131};
10132
10133
10134/**
10135 * Return the coordinate format type used to render the current position or
10136 * undefined.
10137 * @return {ol.CoordinateFormatType|undefined} The format to render the current
10138 * position in.
10139 * @observable
10140 * @api
10141 */
10142ol.control.MousePosition.prototype.getCoordinateFormat = function() {
10143 return /** @type {ol.CoordinateFormatType|undefined} */ (
10144 this.get(ol.control.MousePosition.Property_.COORDINATE_FORMAT));
10145};
10146
10147
10148/**
10149 * Return the projection that is used to report the mouse position.
10150 * @return {ol.proj.Projection|undefined} The projection to report mouse
10151 * position in.
10152 * @observable
10153 * @api
10154 */
10155ol.control.MousePosition.prototype.getProjection = function() {
10156 return /** @type {ol.proj.Projection|undefined} */ (
10157 this.get(ol.control.MousePosition.Property_.PROJECTION));
10158};
10159
10160
10161/**
10162 * @param {Event} event Browser event.
10163 * @protected
10164 */
10165ol.control.MousePosition.prototype.handleMouseMove = function(event) {
10166 var map = this.getMap();
10167 this.lastMouseMovePixel_ = map.getEventPixel(event);
10168 this.updateHTML_(this.lastMouseMovePixel_);
10169};
10170
10171
10172/**
10173 * @param {Event} event Browser event.
10174 * @protected
10175 */
10176ol.control.MousePosition.prototype.handleMouseOut = function(event) {
10177 this.updateHTML_(null);
10178 this.lastMouseMovePixel_ = null;
10179};
10180
10181
10182/**
10183 * @inheritDoc
10184 * @api
10185 */
10186ol.control.MousePosition.prototype.setMap = function(map) {
10187 ol.control.Control.prototype.setMap.call(this, map);
10188 if (map) {
10189 var viewport = map.getViewport();
10190 this.listenerKeys.push(
10191 ol.events.listen(viewport, ol.events.EventType.MOUSEMOVE,
10192 this.handleMouseMove, this),
10193 ol.events.listen(viewport, ol.events.EventType.MOUSEOUT,
10194 this.handleMouseOut, this)
10195 );
10196 }
10197};
10198
10199
10200/**
10201 * Set the coordinate format type used to render the current position.
10202 * @param {ol.CoordinateFormatType} format The format to render the current
10203 * position in.
10204 * @observable
10205 * @api
10206 */
10207ol.control.MousePosition.prototype.setCoordinateFormat = function(format) {
10208 this.set(ol.control.MousePosition.Property_.COORDINATE_FORMAT, format);
10209};
10210
10211
10212/**
10213 * Set the projection that is used to report the mouse position.
10214 * @param {ol.ProjectionLike} projection The projection to report mouse
10215 * position in.
10216 * @observable
10217 * @api
10218 */
10219ol.control.MousePosition.prototype.setProjection = function(projection) {
10220 this.set(ol.control.MousePosition.Property_.PROJECTION, ol.proj.get(projection));
10221};
10222
10223
10224/**
10225 * @param {?ol.Pixel} pixel Pixel.
10226 * @private
10227 */
10228ol.control.MousePosition.prototype.updateHTML_ = function(pixel) {
10229 var html = this.undefinedHTML_;
10230 if (pixel && this.mapProjection_) {
10231 if (!this.transform_) {
10232 var projection = this.getProjection();
10233 if (projection) {
10234 this.transform_ = ol.proj.getTransformFromProjections(
10235 this.mapProjection_, projection);
10236 } else {
10237 this.transform_ = ol.proj.identityTransform;
10238 }
10239 }
10240 var map = this.getMap();
10241 var coordinate = map.getCoordinateFromPixel(pixel);
10242 if (coordinate) {
10243 this.transform_(coordinate, coordinate);
10244 var coordinateFormat = this.getCoordinateFormat();
10245 if (coordinateFormat) {
10246 html = coordinateFormat(coordinate);
10247 } else {
10248 html = coordinate.toString();
10249 }
10250 }
10251 }
10252 if (!this.renderedHTML_ || html != this.renderedHTML_) {
10253 this.element.innerHTML = html;
10254 this.renderedHTML_ = html;
10255 }
10256};
10257
10258
10259/**
10260 * @enum {string}
10261 * @private
10262 */
10263ol.control.MousePosition.Property_ = {
10264 PROJECTION: 'projection',
10265 COORDINATE_FORMAT: 'coordinateFormat'
10266};
10267
10268goog.provide('ol.MapEvent');
10269
10270goog.require('ol');
10271goog.require('ol.events.Event');
10272
10273
10274/**
10275 * @classdesc
10276 * Events emitted as map events are instances of this type.
10277 * See {@link ol.Map} for which events trigger a map event.
10278 *
10279 * @constructor
10280 * @extends {ol.events.Event}
10281 * @implements {oli.MapEvent}
10282 * @param {string} type Event type.
10283 * @param {ol.Map} map Map.
10284 * @param {?olx.FrameState=} opt_frameState Frame state.
10285 */
10286ol.MapEvent = function(type, map, opt_frameState) {
10287
10288 ol.events.Event.call(this, type);
10289
10290 /**
10291 * The map where the event occurred.
10292 * @type {ol.Map}
10293 * @api
10294 */
10295 this.map = map;
10296
10297 /**
10298 * The frame state at the time of the event.
10299 * @type {?olx.FrameState}
10300 * @api
10301 */
10302 this.frameState = opt_frameState !== undefined ? opt_frameState : null;
10303
10304};
10305ol.inherits(ol.MapEvent, ol.events.Event);
10306
10307goog.provide('ol.MapBrowserEvent');
10308
10309goog.require('ol');
10310goog.require('ol.MapEvent');
10311
10312
10313/**
10314 * @classdesc
10315 * Events emitted as map browser events are instances of this type.
10316 * See {@link ol.Map} for which events trigger a map browser event.
10317 *
10318 * @constructor
10319 * @extends {ol.MapEvent}
10320 * @implements {oli.MapBrowserEvent}
10321 * @param {string} type Event type.
10322 * @param {ol.Map} map Map.
10323 * @param {Event} browserEvent Browser event.
10324 * @param {boolean=} opt_dragging Is the map currently being dragged?
10325 * @param {?olx.FrameState=} opt_frameState Frame state.
10326 */
10327ol.MapBrowserEvent = function(type, map, browserEvent, opt_dragging,
10328 opt_frameState) {
10329
10330 ol.MapEvent.call(this, type, map, opt_frameState);
10331
10332 /**
10333 * The original browser event.
10334 * @const
10335 * @type {Event}
10336 * @api
10337 */
10338 this.originalEvent = browserEvent;
10339
10340 /**
10341 * The map pixel relative to the viewport corresponding to the original browser event.
10342 * @type {ol.Pixel}
10343 * @api
10344 */
10345 this.pixel = map.getEventPixel(browserEvent);
10346
10347 /**
10348 * The coordinate in view projection corresponding to the original browser event.
10349 * @type {ol.Coordinate}
10350 * @api
10351 */
10352 this.coordinate = map.getCoordinateFromPixel(this.pixel);
10353
10354 /**
10355 * Indicates if the map is currently being dragged. Only set for
10356 * `POINTERDRAG` and `POINTERMOVE` events. Default is `false`.
10357 *
10358 * @type {boolean}
10359 * @api
10360 */
10361 this.dragging = opt_dragging !== undefined ? opt_dragging : false;
10362
10363};
10364ol.inherits(ol.MapBrowserEvent, ol.MapEvent);
10365
10366
10367/**
10368 * Prevents the default browser action.
10369 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
10370 * @override
10371 * @api
10372 */
10373ol.MapBrowserEvent.prototype.preventDefault = function() {
10374 ol.MapEvent.prototype.preventDefault.call(this);
10375 this.originalEvent.preventDefault();
10376};
10377
10378
10379/**
10380 * Prevents further propagation of the current event.
10381 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
10382 * @override
10383 * @api
10384 */
10385ol.MapBrowserEvent.prototype.stopPropagation = function() {
10386 ol.MapEvent.prototype.stopPropagation.call(this);
10387 this.originalEvent.stopPropagation();
10388};
10389
10390goog.provide('ol.webgl');
10391
10392goog.require('ol');
10393
10394
10395if (ol.ENABLE_WEBGL) {
10396
10397 /** Constants taken from goog.webgl
10398 */
10399
10400
10401 /**
10402 * @const
10403 * @type {number}
10404 */
10405 ol.webgl.ONE = 1;
10406
10407
10408 /**
10409 * @const
10410 * @type {number}
10411 */
10412 ol.webgl.SRC_ALPHA = 0x0302;
10413
10414
10415 /**
10416 * @const
10417 * @type {number}
10418 */
10419 ol.webgl.COLOR_ATTACHMENT0 = 0x8CE0;
10420
10421
10422 /**
10423 * @const
10424 * @type {number}
10425 */
10426 ol.webgl.COLOR_BUFFER_BIT = 0x00004000;
10427
10428
10429 /**
10430 * @const
10431 * @type {number}
10432 */
10433 ol.webgl.TRIANGLES = 0x0004;
10434
10435
10436 /**
10437 * @const
10438 * @type {number}
10439 */
10440 ol.webgl.TRIANGLE_STRIP = 0x0005;
10441
10442
10443 /**
10444 * @const
10445 * @type {number}
10446 */
10447 ol.webgl.ONE_MINUS_SRC_ALPHA = 0x0303;
10448
10449
10450 /**
10451 * @const
10452 * @type {number}
10453 */
10454 ol.webgl.ARRAY_BUFFER = 0x8892;
10455
10456
10457 /**
10458 * @const
10459 * @type {number}
10460 */
10461 ol.webgl.ELEMENT_ARRAY_BUFFER = 0x8893;
10462
10463
10464 /**
10465 * @const
10466 * @type {number}
10467 */
10468 ol.webgl.STREAM_DRAW = 0x88E0;
10469
10470
10471 /**
10472 * @const
10473 * @type {number}
10474 */
10475 ol.webgl.STATIC_DRAW = 0x88E4;
10476
10477
10478 /**
10479 * @const
10480 * @type {number}
10481 */
10482 ol.webgl.DYNAMIC_DRAW = 0x88E8;
10483
10484
10485 /**
10486 * @const
10487 * @type {number}
10488 */
10489 ol.webgl.CULL_FACE = 0x0B44;
10490
10491
10492 /**
10493 * @const
10494 * @type {number}
10495 */
10496 ol.webgl.BLEND = 0x0BE2;
10497
10498
10499 /**
10500 * @const
10501 * @type {number}
10502 */
10503 ol.webgl.STENCIL_TEST = 0x0B90;
10504
10505
10506 /**
10507 * @const
10508 * @type {number}
10509 */
10510 ol.webgl.DEPTH_TEST = 0x0B71;
10511
10512
10513 /**
10514 * @const
10515 * @type {number}
10516 */
10517 ol.webgl.SCISSOR_TEST = 0x0C11;
10518
10519
10520 /**
10521 * @const
10522 * @type {number}
10523 */
10524 ol.webgl.UNSIGNED_BYTE = 0x1401;
10525
10526
10527 /**
10528 * @const
10529 * @type {number}
10530 */
10531 ol.webgl.UNSIGNED_SHORT = 0x1403;
10532
10533
10534 /**
10535 * @const
10536 * @type {number}
10537 */
10538 ol.webgl.UNSIGNED_INT = 0x1405;
10539
10540
10541 /**
10542 * @const
10543 * @type {number}
10544 */
10545 ol.webgl.FLOAT = 0x1406;
10546
10547
10548 /**
10549 * @const
10550 * @type {number}
10551 */
10552 ol.webgl.RGBA = 0x1908;
10553
10554
10555 /**
10556 * @const
10557 * @type {number}
10558 */
10559 ol.webgl.FRAGMENT_SHADER = 0x8B30;
10560
10561
10562 /**
10563 * @const
10564 * @type {number}
10565 */
10566 ol.webgl.VERTEX_SHADER = 0x8B31;
10567
10568
10569 /**
10570 * @const
10571 * @type {number}
10572 */
10573 ol.webgl.LINK_STATUS = 0x8B82;
10574
10575
10576 /**
10577 * @const
10578 * @type {number}
10579 */
10580 ol.webgl.LINEAR = 0x2601;
10581
10582
10583 /**
10584 * @const
10585 * @type {number}
10586 */
10587 ol.webgl.TEXTURE_MAG_FILTER = 0x2800;
10588
10589
10590 /**
10591 * @const
10592 * @type {number}
10593 */
10594 ol.webgl.TEXTURE_MIN_FILTER = 0x2801;
10595
10596
10597 /**
10598 * @const
10599 * @type {number}
10600 */
10601 ol.webgl.TEXTURE_WRAP_S = 0x2802;
10602
10603
10604 /**
10605 * @const
10606 * @type {number}
10607 */
10608 ol.webgl.TEXTURE_WRAP_T = 0x2803;
10609
10610
10611 /**
10612 * @const
10613 * @type {number}
10614 */
10615 ol.webgl.TEXTURE_2D = 0x0DE1;
10616
10617
10618 /**
10619 * @const
10620 * @type {number}
10621 */
10622 ol.webgl.TEXTURE0 = 0x84C0;
10623
10624
10625 /**
10626 * @const
10627 * @type {number}
10628 */
10629 ol.webgl.CLAMP_TO_EDGE = 0x812F;
10630
10631
10632 /**
10633 * @const
10634 * @type {number}
10635 */
10636 ol.webgl.COMPILE_STATUS = 0x8B81;
10637
10638
10639 /**
10640 * @const
10641 * @type {number}
10642 */
10643 ol.webgl.FRAMEBUFFER = 0x8D40;
10644
10645
10646 /** end of goog.webgl constants
10647 */
10648
10649
10650 /**
10651 * @const
10652 * @private
10653 * @type {Array.<string>}
10654 */
10655 ol.webgl.CONTEXT_IDS_ = [
10656 'experimental-webgl',
10657 'webgl',
10658 'webkit-3d',
10659 'moz-webgl'
10660 ];
10661
10662
10663 /**
10664 * @param {HTMLCanvasElement} canvas Canvas.
10665 * @param {Object=} opt_attributes Attributes.
10666 * @return {WebGLRenderingContext} WebGL rendering context.
10667 */
10668 ol.webgl.getContext = function(canvas, opt_attributes) {
10669 var context, i, ii = ol.webgl.CONTEXT_IDS_.length;
10670 for (i = 0; i < ii; ++i) {
10671 try {
10672 context = canvas.getContext(ol.webgl.CONTEXT_IDS_[i], opt_attributes);
10673 if (context) {
10674 return /** @type {!WebGLRenderingContext} */ (context);
10675 }
10676 } catch (e) {
10677 // pass
10678 }
10679 }
10680 return null;
10681 };
10682
10683}
10684
10685goog.provide('ol.has');
10686
10687goog.require('ol');
10688goog.require('ol.webgl');
10689
10690var ua = typeof navigator !== 'undefined' ?
10691 navigator.userAgent.toLowerCase() : '';
10692
10693/**
10694 * User agent string says we are dealing with Firefox as browser.
10695 * @type {boolean}
10696 */
10697ol.has.FIREFOX = ua.indexOf('firefox') !== -1;
10698
10699/**
10700 * User agent string says we are dealing with Safari as browser.
10701 * @type {boolean}
10702 */
10703ol.has.SAFARI = ua.indexOf('safari') !== -1 && ua.indexOf('chrom') == -1;
10704
10705/**
10706 * User agent string says we are dealing with a WebKit engine.
10707 * @type {boolean}
10708 */
10709ol.has.WEBKIT = ua.indexOf('webkit') !== -1 && ua.indexOf('edge') == -1;
10710
10711/**
10712 * User agent string says we are dealing with a Mac as platform.
10713 * @type {boolean}
10714 */
10715ol.has.MAC = ua.indexOf('macintosh') !== -1;
10716
10717
10718/**
10719 * The ratio between physical pixels and device-independent pixels
10720 * (dips) on the device (`window.devicePixelRatio`).
10721 * @const
10722 * @type {number}
10723 * @api
10724 */
10725ol.has.DEVICE_PIXEL_RATIO = window.devicePixelRatio || 1;
10726
10727
10728/**
10729 * True if the browser's Canvas implementation implements {get,set}LineDash.
10730 * @type {boolean}
10731 */
10732ol.has.CANVAS_LINE_DASH = false;
10733
10734
10735/**
10736 * True if both the library and browser support Canvas. Always `false`
10737 * if `ol.ENABLE_CANVAS` is set to `false` at compile time.
10738 * @const
10739 * @type {boolean}
10740 * @api
10741 */
10742ol.has.CANVAS = ol.ENABLE_CANVAS && (
10743 /**
10744 * @return {boolean} Canvas supported.
10745 */
10746 function() {
10747 if (!('HTMLCanvasElement' in window)) {
10748 return false;
10749 }
10750 try {
10751 var context = document.createElement('CANVAS').getContext('2d');
10752 if (!context) {
10753 return false;
10754 } else {
10755 if (context.setLineDash !== undefined) {
10756 ol.has.CANVAS_LINE_DASH = true;
10757 }
10758 return true;
10759 }
10760 } catch (e) {
10761 return false;
10762 }
10763 })();
10764
10765
10766/**
10767 * Indicates if DeviceOrientation is supported in the user's browser.
10768 * @const
10769 * @type {boolean}
10770 * @api
10771 */
10772ol.has.DEVICE_ORIENTATION = 'DeviceOrientationEvent' in window;
10773
10774
10775/**
10776 * Is HTML5 geolocation supported in the current browser?
10777 * @const
10778 * @type {boolean}
10779 * @api
10780 */
10781ol.has.GEOLOCATION = 'geolocation' in navigator;
10782
10783
10784/**
10785 * True if browser supports touch events.
10786 * @const
10787 * @type {boolean}
10788 * @api
10789 */
10790ol.has.TOUCH = ol.ASSUME_TOUCH || 'ontouchstart' in window;
10791
10792
10793/**
10794 * True if browser supports pointer events.
10795 * @const
10796 * @type {boolean}
10797 */
10798ol.has.POINTER = 'PointerEvent' in window;
10799
10800
10801/**
10802 * True if browser supports ms pointer events (IE 10).
10803 * @const
10804 * @type {boolean}
10805 */
10806ol.has.MSPOINTER = !!(navigator.msPointerEnabled);
10807
10808
10809/**
10810 * True if both OpenLayers and browser support WebGL. Always `false`
10811 * if `ol.ENABLE_WEBGL` is set to `false` at compile time.
10812 * @const
10813 * @type {boolean}
10814 * @api
10815 */
10816ol.has.WEBGL;
10817
10818
10819(function() {
10820 if (ol.ENABLE_WEBGL) {
10821 var hasWebGL = false;
10822 var textureSize;
10823 var /** @type {Array.<string>} */ extensions = [];
10824
10825 if ('WebGLRenderingContext' in window) {
10826 try {
10827 var canvas = /** @type {HTMLCanvasElement} */
10828 (document.createElement('CANVAS'));
10829 var gl = ol.webgl.getContext(canvas, {
10830 failIfMajorPerformanceCaveat: true
10831 });
10832 if (gl) {
10833 hasWebGL = true;
10834 textureSize = /** @type {number} */
10835 (gl.getParameter(gl.MAX_TEXTURE_SIZE));
10836 extensions = gl.getSupportedExtensions();
10837 }
10838 } catch (e) {
10839 // pass
10840 }
10841 }
10842 ol.has.WEBGL = hasWebGL;
10843 ol.WEBGL_EXTENSIONS = extensions;
10844 ol.WEBGL_MAX_TEXTURE_SIZE = textureSize;
10845 }
10846})();
10847
10848goog.provide('ol.MapBrowserEventType');
10849
10850goog.require('ol.events.EventType');
10851
10852
10853/**
10854 * Constants for event names.
10855 * @enum {string}
10856 */
10857ol.MapBrowserEventType = {
10858
10859 /**
10860 * A true single click with no dragging and no double click. Note that this
10861 * event is delayed by 250 ms to ensure that it is not a double click.
10862 * @event ol.MapBrowserEvent#singleclick
10863 * @api
10864 */
10865 SINGLECLICK: 'singleclick',
10866
10867 /**
10868 * A click with no dragging. A double click will fire two of this.
10869 * @event ol.MapBrowserEvent#click
10870 * @api
10871 */
10872 CLICK: ol.events.EventType.CLICK,
10873
10874 /**
10875 * A true double click, with no dragging.
10876 * @event ol.MapBrowserEvent#dblclick
10877 * @api
10878 */
10879 DBLCLICK: ol.events.EventType.DBLCLICK,
10880
10881 /**
10882 * Triggered when a pointer is dragged.
10883 * @event ol.MapBrowserEvent#pointerdrag
10884 * @api
10885 */
10886 POINTERDRAG: 'pointerdrag',
10887
10888 /**
10889 * Triggered when a pointer is moved. Note that on touch devices this is
10890 * triggered when the map is panned, so is not the same as mousemove.
10891 * @event ol.MapBrowserEvent#pointermove
10892 * @api
10893 */
10894 POINTERMOVE: 'pointermove',
10895
10896 POINTERDOWN: 'pointerdown',
10897 POINTERUP: 'pointerup',
10898 POINTEROVER: 'pointerover',
10899 POINTEROUT: 'pointerout',
10900 POINTERENTER: 'pointerenter',
10901 POINTERLEAVE: 'pointerleave',
10902 POINTERCANCEL: 'pointercancel'
10903};
10904
10905goog.provide('ol.MapBrowserPointerEvent');
10906
10907goog.require('ol');
10908goog.require('ol.MapBrowserEvent');
10909
10910
10911/**
10912 * @constructor
10913 * @extends {ol.MapBrowserEvent}
10914 * @param {string} type Event type.
10915 * @param {ol.Map} map Map.
10916 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
10917 * @param {boolean=} opt_dragging Is the map currently being dragged?
10918 * @param {?olx.FrameState=} opt_frameState Frame state.
10919 */
10920ol.MapBrowserPointerEvent = function(type, map, pointerEvent, opt_dragging,
10921 opt_frameState) {
10922
10923 ol.MapBrowserEvent.call(this, type, map, pointerEvent.originalEvent, opt_dragging,
10924 opt_frameState);
10925
10926 /**
10927 * @const
10928 * @type {ol.pointer.PointerEvent}
10929 */
10930 this.pointerEvent = pointerEvent;
10931
10932};
10933ol.inherits(ol.MapBrowserPointerEvent, ol.MapBrowserEvent);
10934
10935goog.provide('ol.pointer.EventType');
10936
10937
10938/**
10939 * Constants for event names.
10940 * @enum {string}
10941 */
10942ol.pointer.EventType = {
10943 POINTERMOVE: 'pointermove',
10944 POINTERDOWN: 'pointerdown',
10945 POINTERUP: 'pointerup',
10946 POINTEROVER: 'pointerover',
10947 POINTEROUT: 'pointerout',
10948 POINTERENTER: 'pointerenter',
10949 POINTERLEAVE: 'pointerleave',
10950 POINTERCANCEL: 'pointercancel'
10951};
10952
10953goog.provide('ol.pointer.EventSource');
10954
10955
10956/**
10957 * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
10958 * @param {!Object.<string, function(Event)>} mapping Event
10959 * mapping.
10960 * @constructor
10961 */
10962ol.pointer.EventSource = function(dispatcher, mapping) {
10963 /**
10964 * @type {ol.pointer.PointerEventHandler}
10965 */
10966 this.dispatcher = dispatcher;
10967
10968 /**
10969 * @private
10970 * @const
10971 * @type {!Object.<string, function(Event)>}
10972 */
10973 this.mapping_ = mapping;
10974};
10975
10976
10977/**
10978 * List of events supported by this source.
10979 * @return {Array.<string>} Event names
10980 */
10981ol.pointer.EventSource.prototype.getEvents = function() {
10982 return Object.keys(this.mapping_);
10983};
10984
10985
10986/**
10987 * Returns the handler that should handle a given event type.
10988 * @param {string} eventType The event type.
10989 * @return {function(Event)} Handler
10990 */
10991ol.pointer.EventSource.prototype.getHandlerForEvent = function(eventType) {
10992 return this.mapping_[eventType];
10993};
10994
10995// Based on https://github.com/Polymer/PointerEvents
10996
10997// Copyright (c) 2013 The Polymer Authors. All rights reserved.
10998//
10999// Redistribution and use in source and binary forms, with or without
11000// modification, are permitted provided that the following conditions are
11001// met:
11002//
11003// * Redistributions of source code must retain the above copyright
11004// notice, this list of conditions and the following disclaimer.
11005// * Redistributions in binary form must reproduce the above
11006// copyright notice, this list of conditions and the following disclaimer
11007// in the documentation and/or other materials provided with the
11008// distribution.
11009// * Neither the name of Google Inc. nor the names of its
11010// contributors may be used to endorse or promote products derived from
11011// this software without specific prior written permission.
11012//
11013// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11014// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11015// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11016// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11017// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11018// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11019// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11020// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11021// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11022// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11023// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11024
11025goog.provide('ol.pointer.MouseSource');
11026
11027goog.require('ol');
11028goog.require('ol.pointer.EventSource');
11029
11030
11031/**
11032 * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
11033 * @constructor
11034 * @extends {ol.pointer.EventSource}
11035 */
11036ol.pointer.MouseSource = function(dispatcher) {
11037 var mapping = {
11038 'mousedown': this.mousedown,
11039 'mousemove': this.mousemove,
11040 'mouseup': this.mouseup,
11041 'mouseover': this.mouseover,
11042 'mouseout': this.mouseout
11043 };
11044 ol.pointer.EventSource.call(this, dispatcher, mapping);
11045
11046 /**
11047 * @const
11048 * @type {!Object.<string, Event|Object>}
11049 */
11050 this.pointerMap = dispatcher.pointerMap;
11051
11052 /**
11053 * @const
11054 * @type {Array.<ol.Pixel>}
11055 */
11056 this.lastTouches = [];
11057};
11058ol.inherits(ol.pointer.MouseSource, ol.pointer.EventSource);
11059
11060
11061/**
11062 * @const
11063 * @type {number}
11064 */
11065ol.pointer.MouseSource.POINTER_ID = 1;
11066
11067
11068/**
11069 * @const
11070 * @type {string}
11071 */
11072ol.pointer.MouseSource.POINTER_TYPE = 'mouse';
11073
11074
11075/**
11076 * Radius around touchend that swallows mouse events.
11077 *
11078 * @const
11079 * @type {number}
11080 */
11081ol.pointer.MouseSource.DEDUP_DIST = 25;
11082
11083
11084/**
11085 * Detect if a mouse event was simulated from a touch by
11086 * checking if previously there was a touch event at the
11087 * same position.
11088 *
11089 * FIXME - Known problem with the native Android browser on
11090 * Samsung GT-I9100 (Android 4.1.2):
11091 * In case the page is scrolled, this function does not work
11092 * correctly when a canvas is used (WebGL or canvas renderer).
11093 * Mouse listeners on canvas elements (for this browser), create
11094 * two mouse events: One 'good' and one 'bad' one (on other browsers or
11095 * when a div is used, there is only one event). For the 'bad' one,
11096 * clientX/clientY and also pageX/pageY are wrong when the page
11097 * is scrolled. Because of that, this function can not detect if
11098 * the events were simulated from a touch event. As result, a
11099 * pointer event at a wrong position is dispatched, which confuses
11100 * the map interactions.
11101 * It is unclear, how one can get the correct position for the event
11102 * or detect that the positions are invalid.
11103 *
11104 * @private
11105 * @param {Event} inEvent The in event.
11106 * @return {boolean} True, if the event was generated by a touch.
11107 */
11108ol.pointer.MouseSource.prototype.isEventSimulatedFromTouch_ = function(inEvent) {
11109 var lts = this.lastTouches;
11110 var x = inEvent.clientX, y = inEvent.clientY;
11111 for (var i = 0, l = lts.length, t; i < l && (t = lts[i]); i++) {
11112 // simulated mouse events will be swallowed near a primary touchend
11113 var dx = Math.abs(x - t[0]), dy = Math.abs(y - t[1]);
11114 if (dx <= ol.pointer.MouseSource.DEDUP_DIST &&
11115 dy <= ol.pointer.MouseSource.DEDUP_DIST) {
11116 return true;
11117 }
11118 }
11119 return false;
11120};
11121
11122
11123/**
11124 * Creates a copy of the original event that will be used
11125 * for the fake pointer event.
11126 *
11127 * @param {Event} inEvent The in event.
11128 * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
11129 * @return {Object} The copied event.
11130 */
11131ol.pointer.MouseSource.prepareEvent = function(inEvent, dispatcher) {
11132 var e = dispatcher.cloneEvent(inEvent, inEvent);
11133
11134 // forward mouse preventDefault
11135 var pd = e.preventDefault;
11136 e.preventDefault = function() {
11137 inEvent.preventDefault();
11138 pd();
11139 };
11140
11141 e.pointerId = ol.pointer.MouseSource.POINTER_ID;
11142 e.isPrimary = true;
11143 e.pointerType = ol.pointer.MouseSource.POINTER_TYPE;
11144
11145 return e;
11146};
11147
11148
11149/**
11150 * Handler for `mousedown`.
11151 *
11152 * @param {Event} inEvent The in event.
11153 */
11154ol.pointer.MouseSource.prototype.mousedown = function(inEvent) {
11155 if (!this.isEventSimulatedFromTouch_(inEvent)) {
11156 // TODO(dfreedman) workaround for some elements not sending mouseup
11157 // http://crbug/149091
11158 if (ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap) {
11159 this.cancel(inEvent);
11160 }
11161 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11162 this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()] = inEvent;
11163 this.dispatcher.down(e, inEvent);
11164 }
11165};
11166
11167
11168/**
11169 * Handler for `mousemove`.
11170 *
11171 * @param {Event} inEvent The in event.
11172 */
11173ol.pointer.MouseSource.prototype.mousemove = function(inEvent) {
11174 if (!this.isEventSimulatedFromTouch_(inEvent)) {
11175 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11176 this.dispatcher.move(e, inEvent);
11177 }
11178};
11179
11180
11181/**
11182 * Handler for `mouseup`.
11183 *
11184 * @param {Event} inEvent The in event.
11185 */
11186ol.pointer.MouseSource.prototype.mouseup = function(inEvent) {
11187 if (!this.isEventSimulatedFromTouch_(inEvent)) {
11188 var p = this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];
11189
11190 if (p && p.button === inEvent.button) {
11191 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11192 this.dispatcher.up(e, inEvent);
11193 this.cleanupMouse();
11194 }
11195 }
11196};
11197
11198
11199/**
11200 * Handler for `mouseover`.
11201 *
11202 * @param {Event} inEvent The in event.
11203 */
11204ol.pointer.MouseSource.prototype.mouseover = function(inEvent) {
11205 if (!this.isEventSimulatedFromTouch_(inEvent)) {
11206 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11207 this.dispatcher.enterOver(e, inEvent);
11208 }
11209};
11210
11211
11212/**
11213 * Handler for `mouseout`.
11214 *
11215 * @param {Event} inEvent The in event.
11216 */
11217ol.pointer.MouseSource.prototype.mouseout = function(inEvent) {
11218 if (!this.isEventSimulatedFromTouch_(inEvent)) {
11219 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11220 this.dispatcher.leaveOut(e, inEvent);
11221 }
11222};
11223
11224
11225/**
11226 * Dispatches a `pointercancel` event.
11227 *
11228 * @param {Event} inEvent The in event.
11229 */
11230ol.pointer.MouseSource.prototype.cancel = function(inEvent) {
11231 var e = ol.pointer.MouseSource.prepareEvent(inEvent, this.dispatcher);
11232 this.dispatcher.cancel(e, inEvent);
11233 this.cleanupMouse();
11234};
11235
11236
11237/**
11238 * Remove the mouse from the list of active pointers.
11239 */
11240ol.pointer.MouseSource.prototype.cleanupMouse = function() {
11241 delete this.pointerMap[ol.pointer.MouseSource.POINTER_ID.toString()];
11242};
11243
11244// Based on https://github.com/Polymer/PointerEvents
11245
11246// Copyright (c) 2013 The Polymer Authors. All rights reserved.
11247//
11248// Redistribution and use in source and binary forms, with or without
11249// modification, are permitted provided that the following conditions are
11250// met:
11251//
11252// * Redistributions of source code must retain the above copyright
11253// notice, this list of conditions and the following disclaimer.
11254// * Redistributions in binary form must reproduce the above
11255// copyright notice, this list of conditions and the following disclaimer
11256// in the documentation and/or other materials provided with the
11257// distribution.
11258// * Neither the name of Google Inc. nor the names of its
11259// contributors may be used to endorse or promote products derived from
11260// this software without specific prior written permission.
11261//
11262// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11263// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11264// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11265// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11266// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11267// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11268// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11269// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11270// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11271// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11272// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11273
11274goog.provide('ol.pointer.MsSource');
11275
11276goog.require('ol');
11277goog.require('ol.pointer.EventSource');
11278
11279
11280/**
11281 * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
11282 * @constructor
11283 * @extends {ol.pointer.EventSource}
11284 */
11285ol.pointer.MsSource = function(dispatcher) {
11286 var mapping = {
11287 'MSPointerDown': this.msPointerDown,
11288 'MSPointerMove': this.msPointerMove,
11289 'MSPointerUp': this.msPointerUp,
11290 'MSPointerOut': this.msPointerOut,
11291 'MSPointerOver': this.msPointerOver,
11292 'MSPointerCancel': this.msPointerCancel,
11293 'MSGotPointerCapture': this.msGotPointerCapture,
11294 'MSLostPointerCapture': this.msLostPointerCapture
11295 };
11296 ol.pointer.EventSource.call(this, dispatcher, mapping);
11297
11298 /**
11299 * @const
11300 * @type {!Object.<string, Event|Object>}
11301 */
11302 this.pointerMap = dispatcher.pointerMap;
11303
11304 /**
11305 * @const
11306 * @type {Array.<string>}
11307 */
11308 this.POINTER_TYPES = [
11309 '',
11310 'unavailable',
11311 'touch',
11312 'pen',
11313 'mouse'
11314 ];
11315};
11316ol.inherits(ol.pointer.MsSource, ol.pointer.EventSource);
11317
11318
11319/**
11320 * Creates a copy of the original event that will be used
11321 * for the fake pointer event.
11322 *
11323 * @private
11324 * @param {Event} inEvent The in event.
11325 * @return {Object} The copied event.
11326 */
11327ol.pointer.MsSource.prototype.prepareEvent_ = function(inEvent) {
11328 var e = inEvent;
11329 if (typeof inEvent.pointerType === 'number') {
11330 e = this.dispatcher.cloneEvent(inEvent, inEvent);
11331 e.pointerType = this.POINTER_TYPES[inEvent.pointerType];
11332 }
11333
11334 return e;
11335};
11336
11337
11338/**
11339 * Remove this pointer from the list of active pointers.
11340 * @param {number} pointerId Pointer identifier.
11341 */
11342ol.pointer.MsSource.prototype.cleanup = function(pointerId) {
11343 delete this.pointerMap[pointerId.toString()];
11344};
11345
11346
11347/**
11348 * Handler for `msPointerDown`.
11349 *
11350 * @param {Event} inEvent The in event.
11351 */
11352ol.pointer.MsSource.prototype.msPointerDown = function(inEvent) {
11353 this.pointerMap[inEvent.pointerId.toString()] = inEvent;
11354 var e = this.prepareEvent_(inEvent);
11355 this.dispatcher.down(e, inEvent);
11356};
11357
11358
11359/**
11360 * Handler for `msPointerMove`.
11361 *
11362 * @param {Event} inEvent The in event.
11363 */
11364ol.pointer.MsSource.prototype.msPointerMove = function(inEvent) {
11365 var e = this.prepareEvent_(inEvent);
11366 this.dispatcher.move(e, inEvent);
11367};
11368
11369
11370/**
11371 * Handler for `msPointerUp`.
11372 *
11373 * @param {Event} inEvent The in event.
11374 */
11375ol.pointer.MsSource.prototype.msPointerUp = function(inEvent) {
11376 var e = this.prepareEvent_(inEvent);
11377 this.dispatcher.up(e, inEvent);
11378 this.cleanup(inEvent.pointerId);
11379};
11380
11381
11382/**
11383 * Handler for `msPointerOut`.
11384 *
11385 * @param {Event} inEvent The in event.
11386 */
11387ol.pointer.MsSource.prototype.msPointerOut = function(inEvent) {
11388 var e = this.prepareEvent_(inEvent);
11389 this.dispatcher.leaveOut(e, inEvent);
11390};
11391
11392
11393/**
11394 * Handler for `msPointerOver`.
11395 *
11396 * @param {Event} inEvent The in event.
11397 */
11398ol.pointer.MsSource.prototype.msPointerOver = function(inEvent) {
11399 var e = this.prepareEvent_(inEvent);
11400 this.dispatcher.enterOver(e, inEvent);
11401};
11402
11403
11404/**
11405 * Handler for `msPointerCancel`.
11406 *
11407 * @param {Event} inEvent The in event.
11408 */
11409ol.pointer.MsSource.prototype.msPointerCancel = function(inEvent) {
11410 var e = this.prepareEvent_(inEvent);
11411 this.dispatcher.cancel(e, inEvent);
11412 this.cleanup(inEvent.pointerId);
11413};
11414
11415
11416/**
11417 * Handler for `msLostPointerCapture`.
11418 *
11419 * @param {Event} inEvent The in event.
11420 */
11421ol.pointer.MsSource.prototype.msLostPointerCapture = function(inEvent) {
11422 var e = this.dispatcher.makeEvent('lostpointercapture',
11423 inEvent, inEvent);
11424 this.dispatcher.dispatchEvent(e);
11425};
11426
11427
11428/**
11429 * Handler for `msGotPointerCapture`.
11430 *
11431 * @param {Event} inEvent The in event.
11432 */
11433ol.pointer.MsSource.prototype.msGotPointerCapture = function(inEvent) {
11434 var e = this.dispatcher.makeEvent('gotpointercapture',
11435 inEvent, inEvent);
11436 this.dispatcher.dispatchEvent(e);
11437};
11438
11439// Based on https://github.com/Polymer/PointerEvents
11440
11441// Copyright (c) 2013 The Polymer Authors. All rights reserved.
11442//
11443// Redistribution and use in source and binary forms, with or without
11444// modification, are permitted provided that the following conditions are
11445// met:
11446//
11447// * Redistributions of source code must retain the above copyright
11448// notice, this list of conditions and the following disclaimer.
11449// * Redistributions in binary form must reproduce the above
11450// copyright notice, this list of conditions and the following disclaimer
11451// in the documentation and/or other materials provided with the
11452// distribution.
11453// * Neither the name of Google Inc. nor the names of its
11454// contributors may be used to endorse or promote products derived from
11455// this software without specific prior written permission.
11456//
11457// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11458// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11459// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11460// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11461// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11462// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11463// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11464// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11465// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11466// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11467// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11468
11469goog.provide('ol.pointer.NativeSource');
11470
11471goog.require('ol');
11472goog.require('ol.pointer.EventSource');
11473
11474
11475/**
11476 * @param {ol.pointer.PointerEventHandler} dispatcher Event handler.
11477 * @constructor
11478 * @extends {ol.pointer.EventSource}
11479 */
11480ol.pointer.NativeSource = function(dispatcher) {
11481 var mapping = {
11482 'pointerdown': this.pointerDown,
11483 'pointermove': this.pointerMove,
11484 'pointerup': this.pointerUp,
11485 'pointerout': this.pointerOut,
11486 'pointerover': this.pointerOver,
11487 'pointercancel': this.pointerCancel,
11488 'gotpointercapture': this.gotPointerCapture,
11489 'lostpointercapture': this.lostPointerCapture
11490 };
11491 ol.pointer.EventSource.call(this, dispatcher, mapping);
11492};
11493ol.inherits(ol.pointer.NativeSource, ol.pointer.EventSource);
11494
11495
11496/**
11497 * Handler for `pointerdown`.
11498 *
11499 * @param {Event} inEvent The in event.
11500 */
11501ol.pointer.NativeSource.prototype.pointerDown = function(inEvent) {
11502 this.dispatcher.fireNativeEvent(inEvent);
11503};
11504
11505
11506/**
11507 * Handler for `pointermove`.
11508 *
11509 * @param {Event} inEvent The in event.
11510 */
11511ol.pointer.NativeSource.prototype.pointerMove = function(inEvent) {
11512 this.dispatcher.fireNativeEvent(inEvent);
11513};
11514
11515
11516/**
11517 * Handler for `pointerup`.
11518 *
11519 * @param {Event} inEvent The in event.
11520 */
11521ol.pointer.NativeSource.prototype.pointerUp = function(inEvent) {
11522 this.dispatcher.fireNativeEvent(inEvent);
11523};
11524
11525
11526/**
11527 * Handler for `pointerout`.
11528 *
11529 * @param {Event} inEvent The in event.
11530 */
11531ol.pointer.NativeSource.prototype.pointerOut = function(inEvent) {
11532 this.dispatcher.fireNativeEvent(inEvent);
11533};
11534
11535
11536/**
11537 * Handler for `pointerover`.
11538 *
11539 * @param {Event} inEvent The in event.
11540 */
11541ol.pointer.NativeSource.prototype.pointerOver = function(inEvent) {
11542 this.dispatcher.fireNativeEvent(inEvent);
11543};
11544
11545
11546/**
11547 * Handler for `pointercancel`.
11548 *
11549 * @param {Event} inEvent The in event.
11550 */
11551ol.pointer.NativeSource.prototype.pointerCancel = function(inEvent) {
11552 this.dispatcher.fireNativeEvent(inEvent);
11553};
11554
11555
11556/**
11557 * Handler for `lostpointercapture`.
11558 *
11559 * @param {Event} inEvent The in event.
11560 */
11561ol.pointer.NativeSource.prototype.lostPointerCapture = function(inEvent) {
11562 this.dispatcher.fireNativeEvent(inEvent);
11563};
11564
11565
11566/**
11567 * Handler for `gotpointercapture`.
11568 *
11569 * @param {Event} inEvent The in event.
11570 */
11571ol.pointer.NativeSource.prototype.gotPointerCapture = function(inEvent) {
11572 this.dispatcher.fireNativeEvent(inEvent);
11573};
11574
11575// Based on https://github.com/Polymer/PointerEvents
11576
11577// Copyright (c) 2013 The Polymer Authors. All rights reserved.
11578//
11579// Redistribution and use in source and binary forms, with or without
11580// modification, are permitted provided that the following conditions are
11581// met:
11582//
11583// * Redistributions of source code must retain the above copyright
11584// notice, this list of conditions and the following disclaimer.
11585// * Redistributions in binary form must reproduce the above
11586// copyright notice, this list of conditions and the following disclaimer
11587// in the documentation and/or other materials provided with the
11588// distribution.
11589// * Neither the name of Google Inc. nor the names of its
11590// contributors may be used to endorse or promote products derived from
11591// this software without specific prior written permission.
11592//
11593// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11594// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11595// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11596// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11597// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11598// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11599// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11600// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11601// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11602// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11603// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11604
11605goog.provide('ol.pointer.PointerEvent');
11606
11607
11608goog.require('ol');
11609goog.require('ol.events.Event');
11610
11611
11612/**
11613 * A class for pointer events.
11614 *
11615 * This class is used as an abstraction for mouse events,
11616 * touch events and even native pointer events.
11617 *
11618 * @constructor
11619 * @extends {ol.events.Event}
11620 * @param {string} type The type of the event to create.
11621 * @param {Event} originalEvent The event.
11622 * @param {Object.<string, ?>=} opt_eventDict An optional dictionary of
11623 * initial event properties.
11624 */
11625ol.pointer.PointerEvent = function(type, originalEvent, opt_eventDict) {
11626 ol.events.Event.call(this, type);
11627
11628 /**
11629 * @const
11630 * @type {Event}
11631 */
11632 this.originalEvent = originalEvent;
11633
11634 var eventDict = opt_eventDict ? opt_eventDict : {};
11635
11636 /**
11637 * @type {number}
11638 */
11639 this.buttons = this.getButtons_(eventDict);
11640
11641 /**
11642 * @type {number}
11643 */
11644 this.pressure = this.getPressure_(eventDict, this.buttons);
11645
11646 // MouseEvent related properties
11647
11648 /**
11649 * @type {boolean}
11650 */
11651 this.bubbles = 'bubbles' in eventDict ? eventDict['bubbles'] : false;
11652
11653 /**
11654 * @type {boolean}
11655 */
11656 this.cancelable = 'cancelable' in eventDict ? eventDict['cancelable'] : false;
11657
11658 /**
11659 * @type {Object}
11660 */
11661 this.view = 'view' in eventDict ? eventDict['view'] : null;
11662
11663 /**
11664 * @type {number}
11665 */
11666 this.detail = 'detail' in eventDict ? eventDict['detail'] : null;
11667
11668 /**
11669 * @type {number}
11670 */
11671 this.screenX = 'screenX' in eventDict ? eventDict['screenX'] : 0;
11672
11673 /**
11674 * @type {number}
11675 */
11676 this.screenY = 'screenY' in eventDict ? eventDict['screenY'] : 0;
11677
11678 /**
11679 * @type {number}
11680 */
11681 this.clientX = 'clientX' in eventDict ? eventDict['clientX'] : 0;
11682
11683 /**
11684 * @type {number}
11685 */
11686 this.clientY = 'clientY' in eventDict ? eventDict['clientY'] : 0;
11687
11688 /**
11689 * @type {boolean}
11690 */
11691 this.ctrlKey = 'ctrlKey' in eventDict ? eventDict['ctrlKey'] : false;
11692
11693 /**
11694 * @type {boolean}
11695 */
11696 this.altKey = 'altKey' in eventDict ? eventDict['altKey'] : false;
11697
11698 /**
11699 * @type {boolean}
11700 */
11701 this.shiftKey = 'shiftKey' in eventDict ? eventDict['shiftKey'] : false;
11702
11703 /**
11704 * @type {boolean}
11705 */
11706 this.metaKey = 'metaKey' in eventDict ? eventDict['metaKey'] : false;
11707
11708 /**
11709 * @type {number}
11710 */
11711 this.button = 'button' in eventDict ? eventDict['button'] : 0;
11712
11713 /**
11714 * @type {Node}
11715 */
11716 this.relatedTarget = 'relatedTarget' in eventDict ?
11717 eventDict['relatedTarget'] : null;
11718
11719 // PointerEvent related properties
11720
11721 /**
11722 * @const
11723 * @type {number}
11724 */
11725 this.pointerId = 'pointerId' in eventDict ? eventDict['pointerId'] : 0;
11726
11727 /**
11728 * @type {number}
11729 */
11730 this.width = 'width' in eventDict ? eventDict['width'] : 0;
11731
11732 /**
11733 * @type {number}
11734 */
11735 this.height = 'height' in eventDict ? eventDict['height'] : 0;
11736
11737 /**
11738 * @type {number}
11739 */
11740 this.tiltX = 'tiltX' in eventDict ? eventDict['tiltX'] : 0;
11741
11742 /**
11743 * @type {number}
11744 */
11745 this.tiltY = 'tiltY' in eventDict ? eventDict['tiltY'] : 0;
11746
11747 /**
11748 * @type {string}
11749 */
11750 this.pointerType = 'pointerType' in eventDict ? eventDict['pointerType'] : '';
11751
11752 /**
11753 * @type {number}
11754 */
11755 this.hwTimestamp = 'hwTimestamp' in eventDict ? eventDict['hwTimestamp'] : 0;
11756
11757 /**
11758 * @type {boolean}
11759 */
11760 this.isPrimary = 'isPrimary' in eventDict ? eventDict['isPrimary'] : false;
11761
11762 // keep the semantics of preventDefault
11763 if (originalEvent.preventDefault) {
11764 this.preventDefault = function() {
11765 originalEvent.preventDefault();
11766 };
11767 }
11768};
11769ol.inherits(ol.pointer.PointerEvent, ol.events.Event);
11770
11771
11772/**
11773 * @private
11774 * @param {Object.<string, ?>} eventDict The event dictionary.
11775 * @return {number} Button indicator.
11776 */
11777ol.pointer.PointerEvent.prototype.getButtons_ = function(eventDict) {
11778 // According to the w3c spec,
11779 // http://www.w3.org/TR/DOM-Level-3-Events/#events-MouseEvent-button
11780 // MouseEvent.button == 0 can mean either no mouse button depressed, or the
11781 // left mouse button depressed.
11782 //
11783 // As of now, the only way to distinguish between the two states of
11784 // MouseEvent.button is by using the deprecated MouseEvent.which property, as
11785 // this maps mouse buttons to positive integers > 0, and uses 0 to mean that
11786 // no mouse button is held.
11787 //
11788 // MouseEvent.which is derived from MouseEvent.button at MouseEvent creation,
11789 // but initMouseEvent does not expose an argument with which to set
11790 // MouseEvent.which. Calling initMouseEvent with a buttonArg of 0 will set
11791 // MouseEvent.button == 0 and MouseEvent.which == 1, breaking the expectations
11792 // of app developers.
11793 //
11794 // The only way to propagate the correct state of MouseEvent.which and
11795 // MouseEvent.button to a new MouseEvent.button == 0 and MouseEvent.which == 0
11796 // is to call initMouseEvent with a buttonArg value of -1.
11797 //
11798 // This is fixed with DOM Level 4's use of buttons
11799 var buttons;
11800 if (eventDict.buttons || ol.pointer.PointerEvent.HAS_BUTTONS) {
11801 buttons = eventDict.buttons;
11802 } else {
11803 switch (eventDict.which) {
11804 case 1: buttons = 1; break;
11805 case 2: buttons = 4; break;
11806 case 3: buttons = 2; break;
11807 default: buttons = 0;
11808 }
11809 }
11810 return buttons;
11811};
11812
11813
11814/**
11815 * @private
11816 * @param {Object.<string, ?>} eventDict The event dictionary.
11817 * @param {number} buttons Button indicator.
11818 * @return {number} The pressure.
11819 */
11820ol.pointer.PointerEvent.prototype.getPressure_ = function(eventDict, buttons) {
11821 // Spec requires that pointers without pressure specified use 0.5 for down
11822 // state and 0 for up state.
11823 var pressure = 0;
11824 if (eventDict.pressure) {
11825 pressure = eventDict.pressure;
11826 } else {
11827 pressure = buttons ? 0.5 : 0;
11828 }
11829 return pressure;
11830};
11831
11832
11833/**
11834 * Is the `buttons` property supported?
11835 * @type {boolean}
11836 */
11837ol.pointer.PointerEvent.HAS_BUTTONS = false;
11838
11839
11840/**
11841 * Checks if the `buttons` property is supported.
11842 */
11843(function() {
11844 try {
11845 var ev = new MouseEvent('click', {buttons: 1});
11846 ol.pointer.PointerEvent.HAS_BUTTONS = ev.buttons === 1;
11847 } catch (e) {
11848 // pass
11849 }
11850})();
11851
11852// Based on https://github.com/Polymer/PointerEvents
11853
11854// Copyright (c) 2013 The Polymer Authors. All rights reserved.
11855//
11856// Redistribution and use in source and binary forms, with or without
11857// modification, are permitted provided that the following conditions are
11858// met:
11859//
11860// * Redistributions of source code must retain the above copyright
11861// notice, this list of conditions and the following disclaimer.
11862// * Redistributions in binary form must reproduce the above
11863// copyright notice, this list of conditions and the following disclaimer
11864// in the documentation and/or other materials provided with the
11865// distribution.
11866// * Neither the name of Google Inc. nor the names of its
11867// contributors may be used to endorse or promote products derived from
11868// this software without specific prior written permission.
11869//
11870// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
11871// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11872// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
11873// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
11874// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
11875// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11876// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11877// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11878// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11879// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
11880// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11881
11882goog.provide('ol.pointer.TouchSource');
11883
11884goog.require('ol');
11885goog.require('ol.array');
11886goog.require('ol.pointer.EventSource');
11887goog.require('ol.pointer.MouseSource');
11888
11889
11890/**
11891 * @constructor
11892 * @param {ol.pointer.PointerEventHandler} dispatcher The event handler.
11893 * @param {ol.pointer.MouseSource} mouseSource Mouse source.
11894 * @extends {ol.pointer.EventSource}
11895 */
11896ol.pointer.TouchSource = function(dispatcher, mouseSource) {
11897 var mapping = {
11898 'touchstart': this.touchstart,
11899 'touchmove': this.touchmove,
11900 'touchend': this.touchend,
11901 'touchcancel': this.touchcancel
11902 };
11903 ol.pointer.EventSource.call(this, dispatcher, mapping);
11904
11905 /**
11906 * @const
11907 * @type {!Object.<string, Event|Object>}
11908 */
11909 this.pointerMap = dispatcher.pointerMap;
11910
11911 /**
11912 * @const
11913 * @type {ol.pointer.MouseSource}
11914 */
11915 this.mouseSource = mouseSource;
11916
11917 /**
11918 * @private
11919 * @type {number|undefined}
11920 */
11921 this.firstTouchId_ = undefined;
11922
11923 /**
11924 * @private
11925 * @type {number}
11926 */
11927 this.clickCount_ = 0;
11928
11929 /**
11930 * @private
11931 * @type {number|undefined}
11932 */
11933 this.resetId_ = undefined;
11934};
11935ol.inherits(ol.pointer.TouchSource, ol.pointer.EventSource);
11936
11937
11938/**
11939 * Mouse event timeout: This should be long enough to
11940 * ignore compat mouse events made by touch.
11941 * @const
11942 * @type {number}
11943 */
11944ol.pointer.TouchSource.DEDUP_TIMEOUT = 2500;
11945
11946
11947/**
11948 * @const
11949 * @type {number}
11950 */
11951ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT = 200;
11952
11953
11954/**
11955 * @const
11956 * @type {string}
11957 */
11958ol.pointer.TouchSource.POINTER_TYPE = 'touch';
11959
11960
11961/**
11962 * @private
11963 * @param {Touch} inTouch The in touch.
11964 * @return {boolean} True, if this is the primary touch.
11965 */
11966ol.pointer.TouchSource.prototype.isPrimaryTouch_ = function(inTouch) {
11967 return this.firstTouchId_ === inTouch.identifier;
11968};
11969
11970
11971/**
11972 * Set primary touch if there are no pointers, or the only pointer is the mouse.
11973 * @param {Touch} inTouch The in touch.
11974 * @private
11975 */
11976ol.pointer.TouchSource.prototype.setPrimaryTouch_ = function(inTouch) {
11977 var count = Object.keys(this.pointerMap).length;
11978 if (count === 0 || (count === 1 &&
11979 ol.pointer.MouseSource.POINTER_ID.toString() in this.pointerMap)) {
11980 this.firstTouchId_ = inTouch.identifier;
11981 this.cancelResetClickCount_();
11982 }
11983};
11984
11985
11986/**
11987 * @private
11988 * @param {Object} inPointer The in pointer object.
11989 */
11990ol.pointer.TouchSource.prototype.removePrimaryPointer_ = function(inPointer) {
11991 if (inPointer.isPrimary) {
11992 this.firstTouchId_ = undefined;
11993 this.resetClickCount_();
11994 }
11995};
11996
11997
11998/**
11999 * @private
12000 */
12001ol.pointer.TouchSource.prototype.resetClickCount_ = function() {
12002 this.resetId_ = setTimeout(
12003 this.resetClickCountHandler_.bind(this),
12004 ol.pointer.TouchSource.CLICK_COUNT_TIMEOUT);
12005};
12006
12007
12008/**
12009 * @private
12010 */
12011ol.pointer.TouchSource.prototype.resetClickCountHandler_ = function() {
12012 this.clickCount_ = 0;
12013 this.resetId_ = undefined;
12014};
12015
12016
12017/**
12018 * @private
12019 */
12020ol.pointer.TouchSource.prototype.cancelResetClickCount_ = function() {
12021 if (this.resetId_ !== undefined) {
12022 clearTimeout(this.resetId_);
12023 }
12024};
12025
12026
12027/**
12028 * @private
12029 * @param {Event} browserEvent Browser event
12030 * @param {Touch} inTouch Touch event
12031 * @return {Object} A pointer object.
12032 */
12033ol.pointer.TouchSource.prototype.touchToPointer_ = function(browserEvent, inTouch) {
12034 var e = this.dispatcher.cloneEvent(browserEvent, inTouch);
12035 // Spec specifies that pointerId 1 is reserved for Mouse.
12036 // Touch identifiers can start at 0.
12037 // Add 2 to the touch identifier for compatibility.
12038 e.pointerId = inTouch.identifier + 2;
12039 // TODO: check if this is necessary?
12040 //e.target = findTarget(e);
12041 e.bubbles = true;
12042 e.cancelable = true;
12043 e.detail = this.clickCount_;
12044 e.button = 0;
12045 e.buttons = 1;
12046 e.width = inTouch.webkitRadiusX || inTouch.radiusX || 0;
12047 e.height = inTouch.webkitRadiusY || inTouch.radiusY || 0;
12048 e.pressure = inTouch.webkitForce || inTouch.force || 0.5;
12049 e.isPrimary = this.isPrimaryTouch_(inTouch);
12050 e.pointerType = ol.pointer.TouchSource.POINTER_TYPE;
12051
12052 // make sure that the properties that are different for
12053 // each `Touch` object are not copied from the BrowserEvent object
12054 e.clientX = inTouch.clientX;
12055 e.clientY = inTouch.clientY;
12056 e.screenX = inTouch.screenX;
12057 e.screenY = inTouch.screenY;
12058
12059 return e;
12060};
12061
12062
12063/**
12064 * @private
12065 * @param {Event} inEvent Touch event
12066 * @param {function(Event, Object)} inFunction In function.
12067 */
12068ol.pointer.TouchSource.prototype.processTouches_ = function(inEvent, inFunction) {
12069 var touches = Array.prototype.slice.call(
12070 inEvent.changedTouches);
12071 var count = touches.length;
12072 function preventDefault() {
12073 inEvent.preventDefault();
12074 }
12075 var i, pointer;
12076 for (i = 0; i < count; ++i) {
12077 pointer = this.touchToPointer_(inEvent, touches[i]);
12078 // forward touch preventDefaults
12079 pointer.preventDefault = preventDefault;
12080 inFunction.call(this, inEvent, pointer);
12081 }
12082};
12083
12084
12085/**
12086 * @private
12087 * @param {TouchList} touchList The touch list.
12088 * @param {number} searchId Search identifier.
12089 * @return {boolean} True, if the `Touch` with the given id is in the list.
12090 */
12091ol.pointer.TouchSource.prototype.findTouch_ = function(touchList, searchId) {
12092 var l = touchList.length;
12093 var touch;
12094 for (var i = 0; i < l; i++) {
12095 touch = touchList[i];
12096 if (touch.identifier === searchId) {
12097 return true;
12098 }
12099 }
12100 return false;
12101};
12102
12103
12104/**
12105 * In some instances, a touchstart can happen without a touchend. This
12106 * leaves the pointermap in a broken state.
12107 * Therefore, on every touchstart, we remove the touches that did not fire a
12108 * touchend event.
12109 * To keep state globally consistent, we fire a pointercancel for
12110 * this "abandoned" touch
12111 *
12112 * @private
12113 * @param {Event} inEvent The in event.
12114 */
12115ol.pointer.TouchSource.prototype.vacuumTouches_ = function(inEvent) {
12116 var touchList = inEvent.touches;
12117 // pointerMap.getCount() should be < touchList.length here,
12118 // as the touchstart has not been processed yet.
12119 var keys = Object.keys(this.pointerMap);
12120 var count = keys.length;
12121 if (count >= touchList.length) {
12122 var d = [];
12123 var i, key, value;
12124 for (i = 0; i < count; ++i) {
12125 key = keys[i];
12126 value = this.pointerMap[key];
12127 // Never remove pointerId == 1, which is mouse.
12128 // Touch identifiers are 2 smaller than their pointerId, which is the
12129 // index in pointermap.
12130 if (key != ol.pointer.MouseSource.POINTER_ID &&
12131 !this.findTouch_(touchList, key - 2)) {
12132 d.push(value.out);
12133 }
12134 }
12135 for (i = 0; i < d.length; ++i) {
12136 this.cancelOut_(inEvent, d[i]);
12137 }
12138 }
12139};
12140
12141
12142/**
12143 * Handler for `touchstart`, triggers `pointerover`,
12144 * `pointerenter` and `pointerdown` events.
12145 *
12146 * @param {Event} inEvent The in event.
12147 */
12148ol.pointer.TouchSource.prototype.touchstart = function(inEvent) {
12149 this.vacuumTouches_(inEvent);
12150 this.setPrimaryTouch_(inEvent.changedTouches[0]);
12151 this.dedupSynthMouse_(inEvent);
12152 this.clickCount_++;
12153 this.processTouches_(inEvent, this.overDown_);
12154};
12155
12156
12157/**
12158 * @private
12159 * @param {Event} browserEvent The event.
12160 * @param {Object} inPointer The in pointer object.
12161 */
12162ol.pointer.TouchSource.prototype.overDown_ = function(browserEvent, inPointer) {
12163 this.pointerMap[inPointer.pointerId] = {
12164 target: inPointer.target,
12165 out: inPointer,
12166 outTarget: inPointer.target
12167 };
12168 this.dispatcher.over(inPointer, browserEvent);
12169 this.dispatcher.enter(inPointer, browserEvent);
12170 this.dispatcher.down(inPointer, browserEvent);
12171};
12172
12173
12174/**
12175 * Handler for `touchmove`.
12176 *
12177 * @param {Event} inEvent The in event.
12178 */
12179ol.pointer.TouchSource.prototype.touchmove = function(inEvent) {
12180 inEvent.preventDefault();
12181 this.processTouches_(inEvent, this.moveOverOut_);
12182};
12183
12184
12185/**
12186 * @private
12187 * @param {Event} browserEvent The event.
12188 * @param {Object} inPointer The in pointer.
12189 */
12190ol.pointer.TouchSource.prototype.moveOverOut_ = function(browserEvent, inPointer) {
12191 var event = inPointer;
12192 var pointer = this.pointerMap[event.pointerId];
12193 // a finger drifted off the screen, ignore it
12194 if (!pointer) {
12195 return;
12196 }
12197 var outEvent = pointer.out;
12198 var outTarget = pointer.outTarget;
12199 this.dispatcher.move(event, browserEvent);
12200 if (outEvent && outTarget !== event.target) {
12201 outEvent.relatedTarget = event.target;
12202 event.relatedTarget = outTarget;
12203 // recover from retargeting by shadow
12204 outEvent.target = outTarget;
12205 if (event.target) {
12206 this.dispatcher.leaveOut(outEvent, browserEvent);
12207 this.dispatcher.enterOver(event, browserEvent);
12208 } else {
12209 // clean up case when finger leaves the screen
12210 event.target = outTarget;
12211 event.relatedTarget = null;
12212 this.cancelOut_(browserEvent, event);
12213 }
12214 }
12215 pointer.out = event;
12216 pointer.outTarget = event.target;
12217};
12218
12219
12220/**
12221 * Handler for `touchend`, triggers `pointerup`,
12222 * `pointerout` and `pointerleave` events.
12223 *
12224 * @param {Event} inEvent The event.
12225 */
12226ol.pointer.TouchSource.prototype.touchend = function(inEvent) {
12227 this.dedupSynthMouse_(inEvent);
12228 this.processTouches_(inEvent, this.upOut_);
12229};
12230
12231
12232/**
12233 * @private
12234 * @param {Event} browserEvent An event.
12235 * @param {Object} inPointer The inPointer object.
12236 */
12237ol.pointer.TouchSource.prototype.upOut_ = function(browserEvent, inPointer) {
12238 this.dispatcher.up(inPointer, browserEvent);
12239 this.dispatcher.out(inPointer, browserEvent);
12240 this.dispatcher.leave(inPointer, browserEvent);
12241 this.cleanUpPointer_(inPointer);
12242};
12243
12244
12245/**
12246 * Handler for `touchcancel`, triggers `pointercancel`,
12247 * `pointerout` and `pointerleave` events.
12248 *
12249 * @param {Event} inEvent The in event.
12250 */
12251ol.pointer.TouchSource.prototype.touchcancel = function(inEvent) {
12252 this.processTouches_(inEvent, this.cancelOut_);
12253};
12254
12255
12256/**
12257 * @private
12258 * @param {Event} browserEvent The event.
12259 * @param {Object} inPointer The in pointer.
12260 */
12261ol.pointer.TouchSource.prototype.cancelOut_ = function(browserEvent, inPointer) {
12262 this.dispatcher.cancel(inPointer, browserEvent);
12263 this.dispatcher.out(inPointer, browserEvent);
12264 this.dispatcher.leave(inPointer, browserEvent);
12265 this.cleanUpPointer_(inPointer);
12266};
12267
12268
12269/**
12270 * @private
12271 * @param {Object} inPointer The inPointer object.
12272 */
12273ol.pointer.TouchSource.prototype.cleanUpPointer_ = function(inPointer) {
12274 delete this.pointerMap[inPointer.pointerId];
12275 this.removePrimaryPointer_(inPointer);
12276};
12277
12278
12279/**
12280 * Prevent synth mouse events from creating pointer events.
12281 *
12282 * @private
12283 * @param {Event} inEvent The in event.
12284 */
12285ol.pointer.TouchSource.prototype.dedupSynthMouse_ = function(inEvent) {
12286 var lts = this.mouseSource.lastTouches;
12287 var t = inEvent.changedTouches[0];
12288 // only the primary finger will synth mouse events
12289 if (this.isPrimaryTouch_(t)) {
12290 // remember x/y of last touch
12291 var lt = [t.clientX, t.clientY];
12292 lts.push(lt);
12293
12294 setTimeout(function() {
12295 // remove touch after timeout
12296 ol.array.remove(lts, lt);
12297 }, ol.pointer.TouchSource.DEDUP_TIMEOUT);
12298 }
12299};
12300
12301// Based on https://github.com/Polymer/PointerEvents
12302
12303// Copyright (c) 2013 The Polymer Authors. All rights reserved.
12304//
12305// Redistribution and use in source and binary forms, with or without
12306// modification, are permitted provided that the following conditions are
12307// met:
12308//
12309// * Redistributions of source code must retain the above copyright
12310// notice, this list of conditions and the following disclaimer.
12311// * Redistributions in binary form must reproduce the above
12312// copyright notice, this list of conditions and the following disclaimer
12313// in the documentation and/or other materials provided with the
12314// distribution.
12315// * Neither the name of Google Inc. nor the names of its
12316// contributors may be used to endorse or promote products derived from
12317// this software without specific prior written permission.
12318//
12319// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12320// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12321// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
12322// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
12323// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
12324// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
12325// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12326// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12327// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12328// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
12329// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12330
12331goog.provide('ol.pointer.PointerEventHandler');
12332
12333goog.require('ol');
12334goog.require('ol.events');
12335goog.require('ol.events.EventTarget');
12336
12337goog.require('ol.has');
12338goog.require('ol.pointer.EventType');
12339goog.require('ol.pointer.MouseSource');
12340goog.require('ol.pointer.MsSource');
12341goog.require('ol.pointer.NativeSource');
12342goog.require('ol.pointer.PointerEvent');
12343goog.require('ol.pointer.TouchSource');
12344
12345
12346/**
12347 * @constructor
12348 * @extends {ol.events.EventTarget}
12349 * @param {Element|HTMLDocument} element Viewport element.
12350 */
12351ol.pointer.PointerEventHandler = function(element) {
12352 ol.events.EventTarget.call(this);
12353
12354 /**
12355 * @const
12356 * @private
12357 * @type {Element|HTMLDocument}
12358 */
12359 this.element_ = element;
12360
12361 /**
12362 * @const
12363 * @type {!Object.<string, Event|Object>}
12364 */
12365 this.pointerMap = {};
12366
12367 /**
12368 * @type {Object.<string, function(Event)>}
12369 * @private
12370 */
12371 this.eventMap_ = {};
12372
12373 /**
12374 * @type {Array.<ol.pointer.EventSource>}
12375 * @private
12376 */
12377 this.eventSourceList_ = [];
12378
12379 this.registerSources();
12380};
12381ol.inherits(ol.pointer.PointerEventHandler, ol.events.EventTarget);
12382
12383
12384/**
12385 * Set up the event sources (mouse, touch and native pointers)
12386 * that generate pointer events.
12387 */
12388ol.pointer.PointerEventHandler.prototype.registerSources = function() {
12389 if (ol.has.POINTER) {
12390 this.registerSource('native', new ol.pointer.NativeSource(this));
12391 } else if (ol.has.MSPOINTER) {
12392 this.registerSource('ms', new ol.pointer.MsSource(this));
12393 } else {
12394 var mouseSource = new ol.pointer.MouseSource(this);
12395 this.registerSource('mouse', mouseSource);
12396
12397 if (ol.has.TOUCH) {
12398 this.registerSource('touch',
12399 new ol.pointer.TouchSource(this, mouseSource));
12400 }
12401 }
12402
12403 // register events on the viewport element
12404 this.register_();
12405};
12406
12407
12408/**
12409 * Add a new event source that will generate pointer events.
12410 *
12411 * @param {string} name A name for the event source
12412 * @param {ol.pointer.EventSource} source The source event.
12413 */
12414ol.pointer.PointerEventHandler.prototype.registerSource = function(name, source) {
12415 var s = source;
12416 var newEvents = s.getEvents();
12417
12418 if (newEvents) {
12419 newEvents.forEach(function(e) {
12420 var handler = s.getHandlerForEvent(e);
12421
12422 if (handler) {
12423 this.eventMap_[e] = handler.bind(s);
12424 }
12425 }, this);
12426 this.eventSourceList_.push(s);
12427 }
12428};
12429
12430
12431/**
12432 * Set up the events for all registered event sources.
12433 * @private
12434 */
12435ol.pointer.PointerEventHandler.prototype.register_ = function() {
12436 var l = this.eventSourceList_.length;
12437 var eventSource;
12438 for (var i = 0; i < l; i++) {
12439 eventSource = this.eventSourceList_[i];
12440 this.addEvents_(eventSource.getEvents());
12441 }
12442};
12443
12444
12445/**
12446 * Remove all registered events.
12447 * @private
12448 */
12449ol.pointer.PointerEventHandler.prototype.unregister_ = function() {
12450 var l = this.eventSourceList_.length;
12451 var eventSource;
12452 for (var i = 0; i < l; i++) {
12453 eventSource = this.eventSourceList_[i];
12454 this.removeEvents_(eventSource.getEvents());
12455 }
12456};
12457
12458
12459/**
12460 * Calls the right handler for a new event.
12461 * @private
12462 * @param {Event} inEvent Browser event.
12463 */
12464ol.pointer.PointerEventHandler.prototype.eventHandler_ = function(inEvent) {
12465 var type = inEvent.type;
12466 var handler = this.eventMap_[type];
12467 if (handler) {
12468 handler(inEvent);
12469 }
12470};
12471
12472
12473/**
12474 * Setup listeners for the given events.
12475 * @private
12476 * @param {Array.<string>} events List of events.
12477 */
12478ol.pointer.PointerEventHandler.prototype.addEvents_ = function(events) {
12479 events.forEach(function(eventName) {
12480 ol.events.listen(this.element_, eventName, this.eventHandler_, this);
12481 }, this);
12482};
12483
12484
12485/**
12486 * Unregister listeners for the given events.
12487 * @private
12488 * @param {Array.<string>} events List of events.
12489 */
12490ol.pointer.PointerEventHandler.prototype.removeEvents_ = function(events) {
12491 events.forEach(function(e) {
12492 ol.events.unlisten(this.element_, e, this.eventHandler_, this);
12493 }, this);
12494};
12495
12496
12497/**
12498 * Returns a snapshot of inEvent, with writable properties.
12499 *
12500 * @param {Event} event Browser event.
12501 * @param {Event|Touch} inEvent An event that contains
12502 * properties to copy.
12503 * @return {Object} An object containing shallow copies of
12504 * `inEvent`'s properties.
12505 */
12506ol.pointer.PointerEventHandler.prototype.cloneEvent = function(event, inEvent) {
12507 var eventCopy = {}, p;
12508 for (var i = 0, ii = ol.pointer.PointerEventHandler.CLONE_PROPS.length; i < ii; i++) {
12509 p = ol.pointer.PointerEventHandler.CLONE_PROPS[i][0];
12510 eventCopy[p] = event[p] || inEvent[p] || ol.pointer.PointerEventHandler.CLONE_PROPS[i][1];
12511 }
12512
12513 return eventCopy;
12514};
12515
12516
12517// EVENTS
12518
12519
12520/**
12521 * Triggers a 'pointerdown' event.
12522 * @param {Object} data Pointer event data.
12523 * @param {Event} event The event.
12524 */
12525ol.pointer.PointerEventHandler.prototype.down = function(data, event) {
12526 this.fireEvent(ol.pointer.EventType.POINTERDOWN, data, event);
12527};
12528
12529
12530/**
12531 * Triggers a 'pointermove' event.
12532 * @param {Object} data Pointer event data.
12533 * @param {Event} event The event.
12534 */
12535ol.pointer.PointerEventHandler.prototype.move = function(data, event) {
12536 this.fireEvent(ol.pointer.EventType.POINTERMOVE, data, event);
12537};
12538
12539
12540/**
12541 * Triggers a 'pointerup' event.
12542 * @param {Object} data Pointer event data.
12543 * @param {Event} event The event.
12544 */
12545ol.pointer.PointerEventHandler.prototype.up = function(data, event) {
12546 this.fireEvent(ol.pointer.EventType.POINTERUP, data, event);
12547};
12548
12549
12550/**
12551 * Triggers a 'pointerenter' event.
12552 * @param {Object} data Pointer event data.
12553 * @param {Event} event The event.
12554 */
12555ol.pointer.PointerEventHandler.prototype.enter = function(data, event) {
12556 data.bubbles = false;
12557 this.fireEvent(ol.pointer.EventType.POINTERENTER, data, event);
12558};
12559
12560
12561/**
12562 * Triggers a 'pointerleave' event.
12563 * @param {Object} data Pointer event data.
12564 * @param {Event} event The event.
12565 */
12566ol.pointer.PointerEventHandler.prototype.leave = function(data, event) {
12567 data.bubbles = false;
12568 this.fireEvent(ol.pointer.EventType.POINTERLEAVE, data, event);
12569};
12570
12571
12572/**
12573 * Triggers a 'pointerover' event.
12574 * @param {Object} data Pointer event data.
12575 * @param {Event} event The event.
12576 */
12577ol.pointer.PointerEventHandler.prototype.over = function(data, event) {
12578 data.bubbles = true;
12579 this.fireEvent(ol.pointer.EventType.POINTEROVER, data, event);
12580};
12581
12582
12583/**
12584 * Triggers a 'pointerout' event.
12585 * @param {Object} data Pointer event data.
12586 * @param {Event} event The event.
12587 */
12588ol.pointer.PointerEventHandler.prototype.out = function(data, event) {
12589 data.bubbles = true;
12590 this.fireEvent(ol.pointer.EventType.POINTEROUT, data, event);
12591};
12592
12593
12594/**
12595 * Triggers a 'pointercancel' event.
12596 * @param {Object} data Pointer event data.
12597 * @param {Event} event The event.
12598 */
12599ol.pointer.PointerEventHandler.prototype.cancel = function(data, event) {
12600 this.fireEvent(ol.pointer.EventType.POINTERCANCEL, data, event);
12601};
12602
12603
12604/**
12605 * Triggers a combination of 'pointerout' and 'pointerleave' events.
12606 * @param {Object} data Pointer event data.
12607 * @param {Event} event The event.
12608 */
12609ol.pointer.PointerEventHandler.prototype.leaveOut = function(data, event) {
12610 this.out(data, event);
12611 if (!this.contains_(data.target, data.relatedTarget)) {
12612 this.leave(data, event);
12613 }
12614};
12615
12616
12617/**
12618 * Triggers a combination of 'pointerover' and 'pointerevents' events.
12619 * @param {Object} data Pointer event data.
12620 * @param {Event} event The event.
12621 */
12622ol.pointer.PointerEventHandler.prototype.enterOver = function(data, event) {
12623 this.over(data, event);
12624 if (!this.contains_(data.target, data.relatedTarget)) {
12625 this.enter(data, event);
12626 }
12627};
12628
12629
12630/**
12631 * @private
12632 * @param {Element} container The container element.
12633 * @param {Element} contained The contained element.
12634 * @return {boolean} Returns true if the container element
12635 * contains the other element.
12636 */
12637ol.pointer.PointerEventHandler.prototype.contains_ = function(container, contained) {
12638 if (!container || !contained) {
12639 return false;
12640 }
12641 return container.contains(contained);
12642};
12643
12644
12645// EVENT CREATION AND TRACKING
12646/**
12647 * Creates a new Event of type `inType`, based on the information in
12648 * `data`.
12649 *
12650 * @param {string} inType A string representing the type of event to create.
12651 * @param {Object} data Pointer event data.
12652 * @param {Event} event The event.
12653 * @return {ol.pointer.PointerEvent} A PointerEvent of type `inType`.
12654 */
12655ol.pointer.PointerEventHandler.prototype.makeEvent = function(inType, data, event) {
12656 return new ol.pointer.PointerEvent(inType, event, data);
12657};
12658
12659
12660/**
12661 * Make and dispatch an event in one call.
12662 * @param {string} inType A string representing the type of event.
12663 * @param {Object} data Pointer event data.
12664 * @param {Event} event The event.
12665 */
12666ol.pointer.PointerEventHandler.prototype.fireEvent = function(inType, data, event) {
12667 var e = this.makeEvent(inType, data, event);
12668 this.dispatchEvent(e);
12669};
12670
12671
12672/**
12673 * Creates a pointer event from a native pointer event
12674 * and dispatches this event.
12675 * @param {Event} event A platform event with a target.
12676 */
12677ol.pointer.PointerEventHandler.prototype.fireNativeEvent = function(event) {
12678 var e = this.makeEvent(event.type, event, event);
12679 this.dispatchEvent(e);
12680};
12681
12682
12683/**
12684 * Wrap a native mouse event into a pointer event.
12685 * This proxy method is required for the legacy IE support.
12686 * @param {string} eventType The pointer event type.
12687 * @param {Event} event The event.
12688 * @return {ol.pointer.PointerEvent} The wrapped event.
12689 */
12690ol.pointer.PointerEventHandler.prototype.wrapMouseEvent = function(eventType, event) {
12691 var pointerEvent = this.makeEvent(
12692 eventType, ol.pointer.MouseSource.prepareEvent(event, this), event);
12693 return pointerEvent;
12694};
12695
12696
12697/**
12698 * @inheritDoc
12699 */
12700ol.pointer.PointerEventHandler.prototype.disposeInternal = function() {
12701 this.unregister_();
12702 ol.events.EventTarget.prototype.disposeInternal.call(this);
12703};
12704
12705
12706/**
12707 * Properties to copy when cloning an event, with default values.
12708 * @type {Array.<Array>}
12709 */
12710ol.pointer.PointerEventHandler.CLONE_PROPS = [
12711 // MouseEvent
12712 ['bubbles', false],
12713 ['cancelable', false],
12714 ['view', null],
12715 ['detail', null],
12716 ['screenX', 0],
12717 ['screenY', 0],
12718 ['clientX', 0],
12719 ['clientY', 0],
12720 ['ctrlKey', false],
12721 ['altKey', false],
12722 ['shiftKey', false],
12723 ['metaKey', false],
12724 ['button', 0],
12725 ['relatedTarget', null],
12726 // DOM Level 3
12727 ['buttons', 0],
12728 // PointerEvent
12729 ['pointerId', 0],
12730 ['width', 0],
12731 ['height', 0],
12732 ['pressure', 0],
12733 ['tiltX', 0],
12734 ['tiltY', 0],
12735 ['pointerType', ''],
12736 ['hwTimestamp', 0],
12737 ['isPrimary', false],
12738 // event instance
12739 ['type', ''],
12740 ['target', null],
12741 ['currentTarget', null],
12742 ['which', 0]
12743];
12744
12745goog.provide('ol.MapBrowserEventHandler');
12746
12747goog.require('ol');
12748goog.require('ol.has');
12749goog.require('ol.MapBrowserEventType');
12750goog.require('ol.MapBrowserPointerEvent');
12751goog.require('ol.events');
12752goog.require('ol.events.EventTarget');
12753goog.require('ol.pointer.EventType');
12754goog.require('ol.pointer.PointerEventHandler');
12755
12756
12757/**
12758 * @param {ol.Map} map The map with the viewport to listen to events on.
12759 * @param {number|undefined} moveTolerance The minimal distance the pointer must travel to trigger a move.
12760 * @constructor
12761 * @extends {ol.events.EventTarget}
12762 */
12763ol.MapBrowserEventHandler = function(map, moveTolerance) {
12764
12765 ol.events.EventTarget.call(this);
12766
12767 /**
12768 * This is the element that we will listen to the real events on.
12769 * @type {ol.Map}
12770 * @private
12771 */
12772 this.map_ = map;
12773
12774 /**
12775 * @type {number}
12776 * @private
12777 */
12778 this.clickTimeoutId_ = 0;
12779
12780 /**
12781 * @type {boolean}
12782 * @private
12783 */
12784 this.dragging_ = false;
12785
12786 /**
12787 * @type {!Array.<ol.EventsKey>}
12788 * @private
12789 */
12790 this.dragListenerKeys_ = [];
12791
12792 /**
12793 * @type {number}
12794 * @private
12795 */
12796 this.moveTolerance_ = moveTolerance ?
12797 moveTolerance * ol.has.DEVICE_PIXEL_RATIO : ol.has.DEVICE_PIXEL_RATIO;
12798
12799 /**
12800 * The most recent "down" type event (or null if none have occurred).
12801 * Set on pointerdown.
12802 * @type {ol.pointer.PointerEvent}
12803 * @private
12804 */
12805 this.down_ = null;
12806
12807 var element = this.map_.getViewport();
12808
12809 /**
12810 * @type {number}
12811 * @private
12812 */
12813 this.activePointers_ = 0;
12814
12815 /**
12816 * @type {!Object.<number, boolean>}
12817 * @private
12818 */
12819 this.trackedTouches_ = {};
12820
12821 /**
12822 * Event handler which generates pointer events for
12823 * the viewport element.
12824 *
12825 * @type {ol.pointer.PointerEventHandler}
12826 * @private
12827 */
12828 this.pointerEventHandler_ = new ol.pointer.PointerEventHandler(element);
12829
12830 /**
12831 * Event handler which generates pointer events for
12832 * the document (used when dragging).
12833 *
12834 * @type {ol.pointer.PointerEventHandler}
12835 * @private
12836 */
12837 this.documentPointerEventHandler_ = null;
12838
12839 /**
12840 * @type {?ol.EventsKey}
12841 * @private
12842 */
12843 this.pointerdownListenerKey_ = ol.events.listen(this.pointerEventHandler_,
12844 ol.pointer.EventType.POINTERDOWN,
12845 this.handlePointerDown_, this);
12846
12847 /**
12848 * @type {?ol.EventsKey}
12849 * @private
12850 */
12851 this.relayedListenerKey_ = ol.events.listen(this.pointerEventHandler_,
12852 ol.pointer.EventType.POINTERMOVE,
12853 this.relayEvent_, this);
12854
12855};
12856ol.inherits(ol.MapBrowserEventHandler, ol.events.EventTarget);
12857
12858
12859/**
12860 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12861 * @private
12862 */
12863ol.MapBrowserEventHandler.prototype.emulateClick_ = function(pointerEvent) {
12864 var newEvent = new ol.MapBrowserPointerEvent(
12865 ol.MapBrowserEventType.CLICK, this.map_, pointerEvent);
12866 this.dispatchEvent(newEvent);
12867 if (this.clickTimeoutId_ !== 0) {
12868 // double-click
12869 clearTimeout(this.clickTimeoutId_);
12870 this.clickTimeoutId_ = 0;
12871 newEvent = new ol.MapBrowserPointerEvent(
12872 ol.MapBrowserEventType.DBLCLICK, this.map_, pointerEvent);
12873 this.dispatchEvent(newEvent);
12874 } else {
12875 // click
12876 this.clickTimeoutId_ = setTimeout(function() {
12877 this.clickTimeoutId_ = 0;
12878 var newEvent = new ol.MapBrowserPointerEvent(
12879 ol.MapBrowserEventType.SINGLECLICK, this.map_, pointerEvent);
12880 this.dispatchEvent(newEvent);
12881 }.bind(this), 250);
12882 }
12883};
12884
12885
12886/**
12887 * Keeps track on how many pointers are currently active.
12888 *
12889 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12890 * @private
12891 */
12892ol.MapBrowserEventHandler.prototype.updateActivePointers_ = function(pointerEvent) {
12893 var event = pointerEvent;
12894
12895 if (event.type == ol.MapBrowserEventType.POINTERUP ||
12896 event.type == ol.MapBrowserEventType.POINTERCANCEL) {
12897 delete this.trackedTouches_[event.pointerId];
12898 } else if (event.type == ol.MapBrowserEventType.POINTERDOWN) {
12899 this.trackedTouches_[event.pointerId] = true;
12900 }
12901 this.activePointers_ = Object.keys(this.trackedTouches_).length;
12902};
12903
12904
12905/**
12906 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12907 * @private
12908 */
12909ol.MapBrowserEventHandler.prototype.handlePointerUp_ = function(pointerEvent) {
12910 this.updateActivePointers_(pointerEvent);
12911 var newEvent = new ol.MapBrowserPointerEvent(
12912 ol.MapBrowserEventType.POINTERUP, this.map_, pointerEvent);
12913 this.dispatchEvent(newEvent);
12914
12915 // We emulate click events on left mouse button click, touch contact, and pen
12916 // contact. isMouseActionButton returns true in these cases (evt.button is set
12917 // to 0).
12918 // See http://www.w3.org/TR/pointerevents/#button-states
12919 if (!this.dragging_ && this.isMouseActionButton_(pointerEvent)) {
12920 this.emulateClick_(this.down_);
12921 }
12922
12923 if (this.activePointers_ === 0) {
12924 this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
12925 this.dragListenerKeys_.length = 0;
12926 this.dragging_ = false;
12927 this.down_ = null;
12928 this.documentPointerEventHandler_.dispose();
12929 this.documentPointerEventHandler_ = null;
12930 }
12931};
12932
12933
12934/**
12935 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12936 * @return {boolean} If the left mouse button was pressed.
12937 * @private
12938 */
12939ol.MapBrowserEventHandler.prototype.isMouseActionButton_ = function(pointerEvent) {
12940 return pointerEvent.button === 0;
12941};
12942
12943
12944/**
12945 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12946 * @private
12947 */
12948ol.MapBrowserEventHandler.prototype.handlePointerDown_ = function(pointerEvent) {
12949 this.updateActivePointers_(pointerEvent);
12950 var newEvent = new ol.MapBrowserPointerEvent(
12951 ol.MapBrowserEventType.POINTERDOWN, this.map_, pointerEvent);
12952 this.dispatchEvent(newEvent);
12953
12954 this.down_ = pointerEvent;
12955
12956 if (this.dragListenerKeys_.length === 0) {
12957 /* Set up a pointer event handler on the `document`,
12958 * which is required when the pointer is moved outside
12959 * the viewport when dragging.
12960 */
12961 this.documentPointerEventHandler_ =
12962 new ol.pointer.PointerEventHandler(document);
12963
12964 this.dragListenerKeys_.push(
12965 ol.events.listen(this.documentPointerEventHandler_,
12966 ol.MapBrowserEventType.POINTERMOVE,
12967 this.handlePointerMove_, this),
12968 ol.events.listen(this.documentPointerEventHandler_,
12969 ol.MapBrowserEventType.POINTERUP,
12970 this.handlePointerUp_, this),
12971 /* Note that the listener for `pointercancel is set up on
12972 * `pointerEventHandler_` and not `documentPointerEventHandler_` like
12973 * the `pointerup` and `pointermove` listeners.
12974 *
12975 * The reason for this is the following: `TouchSource.vacuumTouches_()`
12976 * issues `pointercancel` events, when there was no `touchend` for a
12977 * `touchstart`. Now, let's say a first `touchstart` is registered on
12978 * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up.
12979 * But `documentPointerEventHandler_` doesn't know about the first
12980 * `touchstart`. If there is no `touchend` for the `touchstart`, we can
12981 * only receive a `touchcancel` from `pointerEventHandler_`, because it is
12982 * only registered there.
12983 */
12984 ol.events.listen(this.pointerEventHandler_,
12985 ol.MapBrowserEventType.POINTERCANCEL,
12986 this.handlePointerUp_, this)
12987 );
12988 }
12989};
12990
12991
12992/**
12993 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
12994 * @private
12995 */
12996ol.MapBrowserEventHandler.prototype.handlePointerMove_ = function(pointerEvent) {
12997 // Between pointerdown and pointerup, pointermove events are triggered.
12998 // To avoid a 'false' touchmove event to be dispatched, we test if the pointer
12999 // moved a significant distance.
13000 if (this.isMoving_(pointerEvent)) {
13001 this.dragging_ = true;
13002 var newEvent = new ol.MapBrowserPointerEvent(
13003 ol.MapBrowserEventType.POINTERDRAG, this.map_, pointerEvent,
13004 this.dragging_);
13005 this.dispatchEvent(newEvent);
13006 }
13007
13008 // Some native android browser triggers mousemove events during small period
13009 // of time. See: https://code.google.com/p/android/issues/detail?id=5491 or
13010 // https://code.google.com/p/android/issues/detail?id=19827
13011 // ex: Galaxy Tab P3110 + Android 4.1.1
13012 pointerEvent.preventDefault();
13013};
13014
13015
13016/**
13017 * Wrap and relay a pointer event. Note that this requires that the type
13018 * string for the MapBrowserPointerEvent matches the PointerEvent type.
13019 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
13020 * @private
13021 */
13022ol.MapBrowserEventHandler.prototype.relayEvent_ = function(pointerEvent) {
13023 var dragging = !!(this.down_ && this.isMoving_(pointerEvent));
13024 this.dispatchEvent(new ol.MapBrowserPointerEvent(
13025 pointerEvent.type, this.map_, pointerEvent, dragging));
13026};
13027
13028
13029/**
13030 * @param {ol.pointer.PointerEvent} pointerEvent Pointer event.
13031 * @return {boolean} Is moving.
13032 * @private
13033 */
13034ol.MapBrowserEventHandler.prototype.isMoving_ = function(pointerEvent) {
13035 return Math.abs(pointerEvent.clientX - this.down_.clientX) > this.moveTolerance_ ||
13036 Math.abs(pointerEvent.clientY - this.down_.clientY) > this.moveTolerance_;
13037};
13038
13039
13040/**
13041 * @inheritDoc
13042 */
13043ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
13044 if (this.relayedListenerKey_) {
13045 ol.events.unlistenByKey(this.relayedListenerKey_);
13046 this.relayedListenerKey_ = null;
13047 }
13048 if (this.pointerdownListenerKey_) {
13049 ol.events.unlistenByKey(this.pointerdownListenerKey_);
13050 this.pointerdownListenerKey_ = null;
13051 }
13052
13053 this.dragListenerKeys_.forEach(ol.events.unlistenByKey);
13054 this.dragListenerKeys_.length = 0;
13055
13056 if (this.documentPointerEventHandler_) {
13057 this.documentPointerEventHandler_.dispose();
13058 this.documentPointerEventHandler_ = null;
13059 }
13060 if (this.pointerEventHandler_) {
13061 this.pointerEventHandler_.dispose();
13062 this.pointerEventHandler_ = null;
13063 }
13064 ol.events.EventTarget.prototype.disposeInternal.call(this);
13065};
13066
13067goog.provide('ol.MapProperty');
13068
13069/**
13070 * @enum {string}
13071 */
13072ol.MapProperty = {
13073 LAYERGROUP: 'layergroup',
13074 SIZE: 'size',
13075 TARGET: 'target',
13076 VIEW: 'view'
13077};
13078
13079goog.provide('ol.TileState');
13080
13081/**
13082 * @enum {number}
13083 */
13084ol.TileState = {
13085 IDLE: 0,
13086 LOADING: 1,
13087 LOADED: 2,
13088 ERROR: 3,
13089 EMPTY: 4,
13090 ABORT: 5
13091};
13092
13093goog.provide('ol.structs.PriorityQueue');
13094
13095goog.require('ol.asserts');
13096goog.require('ol.obj');
13097
13098
13099/**
13100 * Priority queue.
13101 *
13102 * The implementation is inspired from the Closure Library's Heap class and
13103 * Python's heapq module.
13104 *
13105 * @see http://closure-library.googlecode.com/svn/docs/closure_goog_structs_heap.js.source.html
13106 * @see http://hg.python.org/cpython/file/2.7/Lib/heapq.py
13107 *
13108 * @constructor
13109 * @param {function(T): number} priorityFunction Priority function.
13110 * @param {function(T): string} keyFunction Key function.
13111 * @struct
13112 * @template T
13113 */
13114ol.structs.PriorityQueue = function(priorityFunction, keyFunction) {
13115
13116 /**
13117 * @type {function(T): number}
13118 * @private
13119 */
13120 this.priorityFunction_ = priorityFunction;
13121
13122 /**
13123 * @type {function(T): string}
13124 * @private
13125 */
13126 this.keyFunction_ = keyFunction;
13127
13128 /**
13129 * @type {Array.<T>}
13130 * @private
13131 */
13132 this.elements_ = [];
13133
13134 /**
13135 * @type {Array.<number>}
13136 * @private
13137 */
13138 this.priorities_ = [];
13139
13140 /**
13141 * @type {Object.<string, boolean>}
13142 * @private
13143 */
13144 this.queuedElements_ = {};
13145
13146};
13147
13148
13149/**
13150 * @const
13151 * @type {number}
13152 */
13153ol.structs.PriorityQueue.DROP = Infinity;
13154
13155
13156/**
13157 * FIXME empty description for jsdoc
13158 */
13159ol.structs.PriorityQueue.prototype.clear = function() {
13160 this.elements_.length = 0;
13161 this.priorities_.length = 0;
13162 ol.obj.clear(this.queuedElements_);
13163};
13164
13165
13166/**
13167 * Remove and return the highest-priority element. O(log N).
13168 * @return {T} Element.
13169 */
13170ol.structs.PriorityQueue.prototype.dequeue = function() {
13171 var elements = this.elements_;
13172 var priorities = this.priorities_;
13173 var element = elements[0];
13174 if (elements.length == 1) {
13175 elements.length = 0;
13176 priorities.length = 0;
13177 } else {
13178 elements[0] = elements.pop();
13179 priorities[0] = priorities.pop();
13180 this.siftUp_(0);
13181 }
13182 var elementKey = this.keyFunction_(element);
13183 delete this.queuedElements_[elementKey];
13184 return element;
13185};
13186
13187
13188/**
13189 * Enqueue an element. O(log N).
13190 * @param {T} element Element.
13191 * @return {boolean} The element was added to the queue.
13192 */
13193ol.structs.PriorityQueue.prototype.enqueue = function(element) {
13194 ol.asserts.assert(!(this.keyFunction_(element) in this.queuedElements_),
13195 31); // Tried to enqueue an `element` that was already added to the queue
13196 var priority = this.priorityFunction_(element);
13197 if (priority != ol.structs.PriorityQueue.DROP) {
13198 this.elements_.push(element);
13199 this.priorities_.push(priority);
13200 this.queuedElements_[this.keyFunction_(element)] = true;
13201 this.siftDown_(0, this.elements_.length - 1);
13202 return true;
13203 }
13204 return false;
13205};
13206
13207
13208/**
13209 * @return {number} Count.
13210 */
13211ol.structs.PriorityQueue.prototype.getCount = function() {
13212 return this.elements_.length;
13213};
13214
13215
13216/**
13217 * Gets the index of the left child of the node at the given index.
13218 * @param {number} index The index of the node to get the left child for.
13219 * @return {number} The index of the left child.
13220 * @private
13221 */
13222ol.structs.PriorityQueue.prototype.getLeftChildIndex_ = function(index) {
13223 return index * 2 + 1;
13224};
13225
13226
13227/**
13228 * Gets the index of the right child of the node at the given index.
13229 * @param {number} index The index of the node to get the right child for.
13230 * @return {number} The index of the right child.
13231 * @private
13232 */
13233ol.structs.PriorityQueue.prototype.getRightChildIndex_ = function(index) {
13234 return index * 2 + 2;
13235};
13236
13237
13238/**
13239 * Gets the index of the parent of the node at the given index.
13240 * @param {number} index The index of the node to get the parent for.
13241 * @return {number} The index of the parent.
13242 * @private
13243 */
13244ol.structs.PriorityQueue.prototype.getParentIndex_ = function(index) {
13245 return (index - 1) >> 1;
13246};
13247
13248
13249/**
13250 * Make this a heap. O(N).
13251 * @private
13252 */
13253ol.structs.PriorityQueue.prototype.heapify_ = function() {
13254 var i;
13255 for (i = (this.elements_.length >> 1) - 1; i >= 0; i--) {
13256 this.siftUp_(i);
13257 }
13258};
13259
13260
13261/**
13262 * @return {boolean} Is empty.
13263 */
13264ol.structs.PriorityQueue.prototype.isEmpty = function() {
13265 return this.elements_.length === 0;
13266};
13267
13268
13269/**
13270 * @param {string} key Key.
13271 * @return {boolean} Is key queued.
13272 */
13273ol.structs.PriorityQueue.prototype.isKeyQueued = function(key) {
13274 return key in this.queuedElements_;
13275};
13276
13277
13278/**
13279 * @param {T} element Element.
13280 * @return {boolean} Is queued.
13281 */
13282ol.structs.PriorityQueue.prototype.isQueued = function(element) {
13283 return this.isKeyQueued(this.keyFunction_(element));
13284};
13285
13286
13287/**
13288 * @param {number} index The index of the node to move down.
13289 * @private
13290 */
13291ol.structs.PriorityQueue.prototype.siftUp_ = function(index) {
13292 var elements = this.elements_;
13293 var priorities = this.priorities_;
13294 var count = elements.length;
13295 var element = elements[index];
13296 var priority = priorities[index];
13297 var startIndex = index;
13298
13299 while (index < (count >> 1)) {
13300 var lIndex = this.getLeftChildIndex_(index);
13301 var rIndex = this.getRightChildIndex_(index);
13302
13303 var smallerChildIndex = rIndex < count &&
13304 priorities[rIndex] < priorities[lIndex] ?
13305 rIndex : lIndex;
13306
13307 elements[index] = elements[smallerChildIndex];
13308 priorities[index] = priorities[smallerChildIndex];
13309 index = smallerChildIndex;
13310 }
13311
13312 elements[index] = element;
13313 priorities[index] = priority;
13314 this.siftDown_(startIndex, index);
13315};
13316
13317
13318/**
13319 * @param {number} startIndex The index of the root.
13320 * @param {number} index The index of the node to move up.
13321 * @private
13322 */
13323ol.structs.PriorityQueue.prototype.siftDown_ = function(startIndex, index) {
13324 var elements = this.elements_;
13325 var priorities = this.priorities_;
13326 var element = elements[index];
13327 var priority = priorities[index];
13328
13329 while (index > startIndex) {
13330 var parentIndex = this.getParentIndex_(index);
13331 if (priorities[parentIndex] > priority) {
13332 elements[index] = elements[parentIndex];
13333 priorities[index] = priorities[parentIndex];
13334 index = parentIndex;
13335 } else {
13336 break;
13337 }
13338 }
13339 elements[index] = element;
13340 priorities[index] = priority;
13341};
13342
13343
13344/**
13345 * FIXME empty description for jsdoc
13346 */
13347ol.structs.PriorityQueue.prototype.reprioritize = function() {
13348 var priorityFunction = this.priorityFunction_;
13349 var elements = this.elements_;
13350 var priorities = this.priorities_;
13351 var index = 0;
13352 var n = elements.length;
13353 var element, i, priority;
13354 for (i = 0; i < n; ++i) {
13355 element = elements[i];
13356 priority = priorityFunction(element);
13357 if (priority == ol.structs.PriorityQueue.DROP) {
13358 delete this.queuedElements_[this.keyFunction_(element)];
13359 } else {
13360 priorities[index] = priority;
13361 elements[index++] = element;
13362 }
13363 }
13364 elements.length = index;
13365 priorities.length = index;
13366 this.heapify_();
13367};
13368
13369goog.provide('ol.TileQueue');
13370
13371goog.require('ol');
13372goog.require('ol.TileState');
13373goog.require('ol.events');
13374goog.require('ol.events.EventType');
13375goog.require('ol.structs.PriorityQueue');
13376
13377
13378/**
13379 * @constructor
13380 * @extends {ol.structs.PriorityQueue.<Array>}
13381 * @param {ol.TilePriorityFunction} tilePriorityFunction
13382 * Tile priority function.
13383 * @param {function(): ?} tileChangeCallback
13384 * Function called on each tile change event.
13385 * @struct
13386 */
13387ol.TileQueue = function(tilePriorityFunction, tileChangeCallback) {
13388
13389 ol.structs.PriorityQueue.call(
13390 this,
13391 /**
13392 * @param {Array} element Element.
13393 * @return {number} Priority.
13394 */
13395 function(element) {
13396 return tilePriorityFunction.apply(null, element);
13397 },
13398 /**
13399 * @param {Array} element Element.
13400 * @return {string} Key.
13401 */
13402 function(element) {
13403 return /** @type {ol.Tile} */ (element[0]).getKey();
13404 });
13405
13406 /**
13407 * @private
13408 * @type {function(): ?}
13409 */
13410 this.tileChangeCallback_ = tileChangeCallback;
13411
13412 /**
13413 * @private
13414 * @type {number}
13415 */
13416 this.tilesLoading_ = 0;
13417
13418 /**
13419 * @private
13420 * @type {!Object.<string,boolean>}
13421 */
13422 this.tilesLoadingKeys_ = {};
13423
13424};
13425ol.inherits(ol.TileQueue, ol.structs.PriorityQueue);
13426
13427
13428/**
13429 * @inheritDoc
13430 */
13431ol.TileQueue.prototype.enqueue = function(element) {
13432 var added = ol.structs.PriorityQueue.prototype.enqueue.call(this, element);
13433 if (added) {
13434 var tile = element[0];
13435 ol.events.listen(tile, ol.events.EventType.CHANGE,
13436 this.handleTileChange, this);
13437 }
13438 return added;
13439};
13440
13441
13442/**
13443 * @return {number} Number of tiles loading.
13444 */
13445ol.TileQueue.prototype.getTilesLoading = function() {
13446 return this.tilesLoading_;
13447};
13448
13449
13450/**
13451 * @param {ol.events.Event} event Event.
13452 * @protected
13453 */
13454ol.TileQueue.prototype.handleTileChange = function(event) {
13455 var tile = /** @type {ol.Tile} */ (event.target);
13456 var state = tile.getState();
13457 if (state === ol.TileState.LOADED || state === ol.TileState.ERROR ||
13458 state === ol.TileState.EMPTY || state === ol.TileState.ABORT) {
13459 ol.events.unlisten(tile, ol.events.EventType.CHANGE,
13460 this.handleTileChange, this);
13461 var tileKey = tile.getKey();
13462 if (tileKey in this.tilesLoadingKeys_) {
13463 delete this.tilesLoadingKeys_[tileKey];
13464 --this.tilesLoading_;
13465 }
13466 this.tileChangeCallback_();
13467 }
13468};
13469
13470
13471/**
13472 * @param {number} maxTotalLoading Maximum number tiles to load simultaneously.
13473 * @param {number} maxNewLoads Maximum number of new tiles to load.
13474 */
13475ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
13476 var newLoads = 0;
13477 var abortedTiles = false;
13478 var state, tile, tileKey;
13479 while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
13480 this.getCount() > 0) {
13481 tile = /** @type {ol.Tile} */ (this.dequeue()[0]);
13482 tileKey = tile.getKey();
13483 state = tile.getState();
13484 if (state === ol.TileState.ABORT) {
13485 abortedTiles = true;
13486 } else if (state === ol.TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
13487 this.tilesLoadingKeys_[tileKey] = true;
13488 ++this.tilesLoading_;
13489 ++newLoads;
13490 tile.load();
13491 }
13492 }
13493 if (newLoads === 0 && abortedTiles) {
13494 // Do not stop the render loop when all wanted tiles were aborted due to
13495 // a small, saturated tile cache.
13496 this.tileChangeCallback_();
13497 }
13498};
13499
13500goog.provide('ol.ResolutionConstraint');
13501
13502goog.require('ol.array');
13503goog.require('ol.math');
13504
13505
13506/**
13507 * @param {Array.<number>} resolutions Resolutions.
13508 * @return {ol.ResolutionConstraintType} Zoom function.
13509 */
13510ol.ResolutionConstraint.createSnapToResolutions = function(resolutions) {
13511 return (
13512 /**
13513 * @param {number|undefined} resolution Resolution.
13514 * @param {number} delta Delta.
13515 * @param {number} direction Direction.
13516 * @return {number|undefined} Resolution.
13517 */
13518 function(resolution, delta, direction) {
13519 if (resolution !== undefined) {
13520 var z =
13521 ol.array.linearFindNearest(resolutions, resolution, direction);
13522 z = ol.math.clamp(z + delta, 0, resolutions.length - 1);
13523 var index = Math.floor(z);
13524 if (z != index && index < resolutions.length - 1) {
13525 var power = resolutions[index] / resolutions[index + 1];
13526 return resolutions[index] / Math.pow(power, z - index);
13527 } else {
13528 return resolutions[index];
13529 }
13530 } else {
13531 return undefined;
13532 }
13533 });
13534};
13535
13536
13537/**
13538 * @param {number} power Power.
13539 * @param {number} maxResolution Maximum resolution.
13540 * @param {number=} opt_maxLevel Maximum level.
13541 * @return {ol.ResolutionConstraintType} Zoom function.
13542 */
13543ol.ResolutionConstraint.createSnapToPower = function(power, maxResolution, opt_maxLevel) {
13544 return (
13545 /**
13546 * @param {number|undefined} resolution Resolution.
13547 * @param {number} delta Delta.
13548 * @param {number} direction Direction.
13549 * @return {number|undefined} Resolution.
13550 */
13551 function(resolution, delta, direction) {
13552 if (resolution !== undefined) {
13553 var offset = -direction / 2 + 0.5;
13554 var oldLevel = Math.floor(
13555 Math.log(maxResolution / resolution) / Math.log(power) + offset);
13556 var newLevel = Math.max(oldLevel + delta, 0);
13557 if (opt_maxLevel !== undefined) {
13558 newLevel = Math.min(newLevel, opt_maxLevel);
13559 }
13560 return maxResolution / Math.pow(power, newLevel);
13561 } else {
13562 return undefined;
13563 }
13564 });
13565};
13566
13567goog.provide('ol.RotationConstraint');
13568
13569goog.require('ol.math');
13570
13571
13572/**
13573 * @param {number|undefined} rotation Rotation.
13574 * @param {number} delta Delta.
13575 * @return {number|undefined} Rotation.
13576 */
13577ol.RotationConstraint.disable = function(rotation, delta) {
13578 if (rotation !== undefined) {
13579 return 0;
13580 } else {
13581 return undefined;
13582 }
13583};
13584
13585
13586/**
13587 * @param {number|undefined} rotation Rotation.
13588 * @param {number} delta Delta.
13589 * @return {number|undefined} Rotation.
13590 */
13591ol.RotationConstraint.none = function(rotation, delta) {
13592 if (rotation !== undefined) {
13593 return rotation + delta;
13594 } else {
13595 return undefined;
13596 }
13597};
13598
13599
13600/**
13601 * @param {number} n N.
13602 * @return {ol.RotationConstraintType} Rotation constraint.
13603 */
13604ol.RotationConstraint.createSnapToN = function(n) {
13605 var theta = 2 * Math.PI / n;
13606 return (
13607 /**
13608 * @param {number|undefined} rotation Rotation.
13609 * @param {number} delta Delta.
13610 * @return {number|undefined} Rotation.
13611 */
13612 function(rotation, delta) {
13613 if (rotation !== undefined) {
13614 rotation = Math.floor((rotation + delta) / theta + 0.5) * theta;
13615 return rotation;
13616 } else {
13617 return undefined;
13618 }
13619 });
13620};
13621
13622
13623/**
13624 * @param {number=} opt_tolerance Tolerance.
13625 * @return {ol.RotationConstraintType} Rotation constraint.
13626 */
13627ol.RotationConstraint.createSnapToZero = function(opt_tolerance) {
13628 var tolerance = opt_tolerance || ol.math.toRadians(5);
13629 return (
13630 /**
13631 * @param {number|undefined} rotation Rotation.
13632 * @param {number} delta Delta.
13633 * @return {number|undefined} Rotation.
13634 */
13635 function(rotation, delta) {
13636 if (rotation !== undefined) {
13637 if (Math.abs(rotation + delta) <= tolerance) {
13638 return 0;
13639 } else {
13640 return rotation + delta;
13641 }
13642 } else {
13643 return undefined;
13644 }
13645 });
13646};
13647
13648goog.provide('ol.ViewHint');
13649
13650/**
13651 * @enum {number}
13652 */
13653ol.ViewHint = {
13654 ANIMATING: 0,
13655 INTERACTING: 1
13656};
13657
13658goog.provide('ol.ViewProperty');
13659
13660/**
13661 * @enum {string}
13662 */
13663ol.ViewProperty = {
13664 CENTER: 'center',
13665 RESOLUTION: 'resolution',
13666 ROTATION: 'rotation'
13667};
13668
13669goog.provide('ol.string');
13670
13671/**
13672 * @param {number} number Number to be formatted
13673 * @param {number} width The desired width
13674 * @param {number=} opt_precision Precision of the output string (i.e. number of decimal places)
13675 * @returns {string} Formatted string
13676*/
13677ol.string.padNumber = function(number, width, opt_precision) {
13678 var numberString = opt_precision !== undefined ? number.toFixed(opt_precision) : '' + number;
13679 var decimal = numberString.indexOf('.');
13680 decimal = decimal === -1 ? numberString.length : decimal;
13681 return decimal > width ? numberString : new Array(1 + width - decimal).join('0') + numberString;
13682};
13683
13684/**
13685 * Adapted from https://github.com/omichelsen/compare-versions/blob/master/index.js
13686 * @param {string|number} v1 First version
13687 * @param {string|number} v2 Second version
13688 * @returns {number} Value
13689 */
13690ol.string.compareVersions = function(v1, v2) {
13691 var s1 = ('' + v1).split('.');
13692 var s2 = ('' + v2).split('.');
13693
13694 for (var i = 0; i < Math.max(s1.length, s2.length); i++) {
13695 var n1 = parseInt(s1[i] || '0', 10);
13696 var n2 = parseInt(s2[i] || '0', 10);
13697
13698 if (n1 > n2) {
13699 return 1;
13700 }
13701 if (n2 > n1) {
13702 return -1;
13703 }
13704 }
13705
13706 return 0;
13707};
13708
13709goog.provide('ol.coordinate');
13710
13711goog.require('ol.math');
13712goog.require('ol.string');
13713
13714
13715/**
13716 * Add `delta` to `coordinate`. `coordinate` is modified in place and returned
13717 * by the function.
13718 *
13719 * Example:
13720 *
13721 * var coord = [7.85, 47.983333];
13722 * ol.coordinate.add(coord, [-2, 4]);
13723 * // coord is now [5.85, 51.983333]
13724 *
13725 * @param {ol.Coordinate} coordinate Coordinate.
13726 * @param {ol.Coordinate} delta Delta.
13727 * @return {ol.Coordinate} The input coordinate adjusted by the given delta.
13728 * @api
13729 */
13730ol.coordinate.add = function(coordinate, delta) {
13731 coordinate[0] += delta[0];
13732 coordinate[1] += delta[1];
13733 return coordinate;
13734};
13735
13736
13737/**
13738 * Calculates the point closest to the passed coordinate on the passed circle.
13739 *
13740 * @param {ol.Coordinate} coordinate The coordinate.
13741 * @param {ol.geom.Circle} circle The circle.
13742 * @return {ol.Coordinate} Closest point on the circumference
13743 */
13744ol.coordinate.closestOnCircle = function(coordinate, circle) {
13745 var r = circle.getRadius();
13746 var center = circle.getCenter();
13747 var x0 = center[0];
13748 var y0 = center[1];
13749 var x1 = coordinate[0];
13750 var y1 = coordinate[1];
13751
13752 var dx = x1 - x0;
13753 var dy = y1 - y0;
13754 if (dx === 0 && dy === 0) {
13755 dx = 1;
13756 }
13757 var d = Math.sqrt(dx * dx + dy * dy);
13758
13759 var x, y;
13760
13761 x = x0 + r * dx / d;
13762 y = y0 + r * dy / d;
13763
13764 return [x, y];
13765};
13766
13767
13768/**
13769 * Calculates the point closest to the passed coordinate on the passed segment.
13770 * This is the foot of the perpendicular of the coordinate to the segment when
13771 * the foot is on the segment, or the closest segment coordinate when the foot
13772 * is outside the segment.
13773 *
13774 * @param {ol.Coordinate} coordinate The coordinate.
13775 * @param {Array.<ol.Coordinate>} segment The two coordinates of the segment.
13776 * @return {ol.Coordinate} The foot of the perpendicular of the coordinate to
13777 * the segment.
13778 */
13779ol.coordinate.closestOnSegment = function(coordinate, segment) {
13780 var x0 = coordinate[0];
13781 var y0 = coordinate[1];
13782 var start = segment[0];
13783 var end = segment[1];
13784 var x1 = start[0];
13785 var y1 = start[1];
13786 var x2 = end[0];
13787 var y2 = end[1];
13788 var dx = x2 - x1;
13789 var dy = y2 - y1;
13790 var along = (dx === 0 && dy === 0) ? 0 :
13791 ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0);
13792 var x, y;
13793 if (along <= 0) {
13794 x = x1;
13795 y = y1;
13796 } else if (along >= 1) {
13797 x = x2;
13798 y = y2;
13799 } else {
13800 x = x1 + along * dx;
13801 y = y1 + along * dy;
13802 }
13803 return [x, y];
13804};
13805
13806
13807/**
13808 * Returns a {@link ol.CoordinateFormatType} function that can be used to format
13809 * a {ol.Coordinate} to a string.
13810 *
13811 * Example without specifying the fractional digits:
13812 *
13813 * var coord = [7.85, 47.983333];
13814 * var stringifyFunc = ol.coordinate.createStringXY();
13815 * var out = stringifyFunc(coord);
13816 * // out is now '8, 48'
13817 *
13818 * Example with explicitly specifying 2 fractional digits:
13819 *
13820 * var coord = [7.85, 47.983333];
13821 * var stringifyFunc = ol.coordinate.createStringXY(2);
13822 * var out = stringifyFunc(coord);
13823 * // out is now '7.85, 47.98'
13824 *
13825 * @param {number=} opt_fractionDigits The number of digits to include
13826 * after the decimal point. Default is `0`.
13827 * @return {ol.CoordinateFormatType} Coordinate format.
13828 * @api
13829 */
13830ol.coordinate.createStringXY = function(opt_fractionDigits) {
13831 return (
13832 /**
13833 * @param {ol.Coordinate|undefined} coordinate Coordinate.
13834 * @return {string} String XY.
13835 */
13836 function(coordinate) {
13837 return ol.coordinate.toStringXY(coordinate, opt_fractionDigits);
13838 });
13839};
13840
13841
13842/**
13843 * @param {string} hemispheres Hemispheres.
13844 * @param {number} degrees Degrees.
13845 * @param {number=} opt_fractionDigits The number of digits to include
13846 * after the decimal point. Default is `0`.
13847 * @return {string} String.
13848 */
13849ol.coordinate.degreesToStringHDMS = function(hemispheres, degrees, opt_fractionDigits) {
13850 var normalizedDegrees = ol.math.modulo(degrees + 180, 360) - 180;
13851 var x = Math.abs(3600 * normalizedDegrees);
13852 var dflPrecision = opt_fractionDigits || 0;
13853 var precision = Math.pow(10, dflPrecision);
13854
13855 var deg = Math.floor(x / 3600);
13856 var min = Math.floor((x - deg * 3600) / 60);
13857 var sec = x - (deg * 3600) - (min * 60);
13858 sec = Math.ceil(sec * precision) / precision;
13859
13860 if (sec >= 60) {
13861 sec = 0;
13862 min += 1;
13863 }
13864
13865 if (min >= 60) {
13866 min = 0;
13867 deg += 1;
13868 }
13869
13870 return deg + '\u00b0 ' + ol.string.padNumber(min, 2) + '\u2032 ' +
13871 ol.string.padNumber(sec, 2, dflPrecision) + '\u2033' +
13872 (normalizedDegrees == 0 ? '' : ' ' + hemispheres.charAt(normalizedDegrees < 0 ? 1 : 0));
13873};
13874
13875
13876/**
13877 * Transforms the given {@link ol.Coordinate} to a string using the given string
13878 * template. The strings `{x}` and `{y}` in the template will be replaced with
13879 * the first and second coordinate values respectively.
13880 *
13881 * Example without specifying the fractional digits:
13882 *
13883 * var coord = [7.85, 47.983333];
13884 * var template = 'Coordinate is ({x}|{y}).';
13885 * var out = ol.coordinate.format(coord, template);
13886 * // out is now 'Coordinate is (8|48).'
13887 *
13888 * Example explicitly specifying the fractional digits:
13889 *
13890 * var coord = [7.85, 47.983333];
13891 * var template = 'Coordinate is ({x}|{y}).';
13892 * var out = ol.coordinate.format(coord, template, 2);
13893 * // out is now 'Coordinate is (7.85|47.98).'
13894 *
13895 * @param {ol.Coordinate|undefined} coordinate Coordinate.
13896 * @param {string} template A template string with `{x}` and `{y}` placeholders
13897 * that will be replaced by first and second coordinate values.
13898 * @param {number=} opt_fractionDigits The number of digits to include
13899 * after the decimal point. Default is `0`.
13900 * @return {string} Formatted coordinate.
13901 * @api
13902 */
13903ol.coordinate.format = function(coordinate, template, opt_fractionDigits) {
13904 if (coordinate) {
13905 return template
13906 .replace('{x}', coordinate[0].toFixed(opt_fractionDigits))
13907 .replace('{y}', coordinate[1].toFixed(opt_fractionDigits));
13908 } else {
13909 return '';
13910 }
13911};
13912
13913
13914/**
13915 * @param {ol.Coordinate} coordinate1 First coordinate.
13916 * @param {ol.Coordinate} coordinate2 Second coordinate.
13917 * @return {boolean} Whether the passed coordinates are equal.
13918 */
13919ol.coordinate.equals = function(coordinate1, coordinate2) {
13920 var equals = true;
13921 for (var i = coordinate1.length - 1; i >= 0; --i) {
13922 if (coordinate1[i] != coordinate2[i]) {
13923 equals = false;
13924 break;
13925 }
13926 }
13927 return equals;
13928};
13929
13930
13931/**
13932 * Rotate `coordinate` by `angle`. `coordinate` is modified in place and
13933 * returned by the function.
13934 *
13935 * Example:
13936 *
13937 * var coord = [7.85, 47.983333];
13938 * var rotateRadians = Math.PI / 2; // 90 degrees
13939 * ol.coordinate.rotate(coord, rotateRadians);
13940 * // coord is now [-47.983333, 7.85]
13941 *
13942 * @param {ol.Coordinate} coordinate Coordinate.
13943 * @param {number} angle Angle in radian.
13944 * @return {ol.Coordinate} Coordinate.
13945 * @api
13946 */
13947ol.coordinate.rotate = function(coordinate, angle) {
13948 var cosAngle = Math.cos(angle);
13949 var sinAngle = Math.sin(angle);
13950 var x = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
13951 var y = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
13952 coordinate[0] = x;
13953 coordinate[1] = y;
13954 return coordinate;
13955};
13956
13957
13958/**
13959 * Scale `coordinate` by `scale`. `coordinate` is modified in place and returned
13960 * by the function.
13961 *
13962 * Example:
13963 *
13964 * var coord = [7.85, 47.983333];
13965 * var scale = 1.2;
13966 * ol.coordinate.scale(coord, scale);
13967 * // coord is now [9.42, 57.5799996]
13968 *
13969 * @param {ol.Coordinate} coordinate Coordinate.
13970 * @param {number} scale Scale factor.
13971 * @return {ol.Coordinate} Coordinate.
13972 */
13973ol.coordinate.scale = function(coordinate, scale) {
13974 coordinate[0] *= scale;
13975 coordinate[1] *= scale;
13976 return coordinate;
13977};
13978
13979
13980/**
13981 * Subtract `delta` to `coordinate`. `coordinate` is modified in place and
13982 * returned by the function.
13983 *
13984 * @param {ol.Coordinate} coordinate Coordinate.
13985 * @param {ol.Coordinate} delta Delta.
13986 * @return {ol.Coordinate} Coordinate.
13987 */
13988ol.coordinate.sub = function(coordinate, delta) {
13989 coordinate[0] -= delta[0];
13990 coordinate[1] -= delta[1];
13991 return coordinate;
13992};
13993
13994
13995/**
13996 * @param {ol.Coordinate} coord1 First coordinate.
13997 * @param {ol.Coordinate} coord2 Second coordinate.
13998 * @return {number} Squared distance between coord1 and coord2.
13999 */
14000ol.coordinate.squaredDistance = function(coord1, coord2) {
14001 var dx = coord1[0] - coord2[0];
14002 var dy = coord1[1] - coord2[1];
14003 return dx * dx + dy * dy;
14004};
14005
14006
14007/**
14008 * @param {ol.Coordinate} coord1 First coordinate.
14009 * @param {ol.Coordinate} coord2 Second coordinate.
14010 * @return {number} Distance between coord1 and coord2.
14011 */
14012ol.coordinate.distance = function(coord1, coord2) {
14013 return Math.sqrt(ol.coordinate.squaredDistance(coord1, coord2));
14014};
14015
14016
14017/**
14018 * Calculate the squared distance from a coordinate to a line segment.
14019 *
14020 * @param {ol.Coordinate} coordinate Coordinate of the point.
14021 * @param {Array.<ol.Coordinate>} segment Line segment (2 coordinates).
14022 * @return {number} Squared distance from the point to the line segment.
14023 */
14024ol.coordinate.squaredDistanceToSegment = function(coordinate, segment) {
14025 return ol.coordinate.squaredDistance(coordinate,
14026 ol.coordinate.closestOnSegment(coordinate, segment));
14027};
14028
14029
14030/**
14031 * Format a geographic coordinate with the hemisphere, degrees, minutes, and
14032 * seconds.
14033 *
14034 * Example without specifying fractional digits:
14035 *
14036 * var coord = [7.85, 47.983333];
14037 * var out = ol.coordinate.toStringHDMS(coord);
14038 * // out is now '47° 58′ 60″ N 7° 50′ 60″ E'
14039 *
14040 * Example explicitly specifying 1 fractional digit:
14041 *
14042 * var coord = [7.85, 47.983333];
14043 * var out = ol.coordinate.toStringHDMS(coord, 1);
14044 * // out is now '47° 58′ 60.0″ N 7° 50′ 60.0″ E'
14045 *
14046 * @param {ol.Coordinate|undefined} coordinate Coordinate.
14047 * @param {number=} opt_fractionDigits The number of digits to include
14048 * after the decimal point. Default is `0`.
14049 * @return {string} Hemisphere, degrees, minutes and seconds.
14050 * @api
14051 */
14052ol.coordinate.toStringHDMS = function(coordinate, opt_fractionDigits) {
14053 if (coordinate) {
14054 return ol.coordinate.degreesToStringHDMS('NS', coordinate[1], opt_fractionDigits) + ' ' +
14055 ol.coordinate.degreesToStringHDMS('EW', coordinate[0], opt_fractionDigits);
14056 } else {
14057 return '';
14058 }
14059};
14060
14061
14062/**
14063 * Format a coordinate as a comma delimited string.
14064 *
14065 * Example without specifying fractional digits:
14066 *
14067 * var coord = [7.85, 47.983333];
14068 * var out = ol.coordinate.toStringXY(coord);
14069 * // out is now '8, 48'
14070 *
14071 * Example explicitly specifying 1 fractional digit:
14072 *
14073 * var coord = [7.85, 47.983333];
14074 * var out = ol.coordinate.toStringXY(coord, 1);
14075 * // out is now '7.8, 48.0'
14076 *
14077 * @param {ol.Coordinate|undefined} coordinate Coordinate.
14078 * @param {number=} opt_fractionDigits The number of digits to include
14079 * after the decimal point. Default is `0`.
14080 * @return {string} XY.
14081 * @api
14082 */
14083ol.coordinate.toStringXY = function(coordinate, opt_fractionDigits) {
14084 return ol.coordinate.format(coordinate, '{x}, {y}', opt_fractionDigits);
14085};
14086
14087goog.provide('ol.geom.GeometryLayout');
14088
14089
14090/**
14091 * The coordinate layout for geometries, indicating whether a 3rd or 4th z ('Z')
14092 * or measure ('M') coordinate is available. Supported values are `'XY'`,
14093 * `'XYZ'`, `'XYM'`, `'XYZM'`.
14094 * @enum {string}
14095 */
14096ol.geom.GeometryLayout = {
14097 XY: 'XY',
14098 XYZ: 'XYZ',
14099 XYM: 'XYM',
14100 XYZM: 'XYZM'
14101};
14102
14103goog.provide('ol.functions');
14104
14105/**
14106 * Always returns true.
14107 * @returns {boolean} true.
14108 */
14109ol.functions.TRUE = function() {
14110 return true;
14111};
14112
14113/**
14114 * Always returns false.
14115 * @returns {boolean} false.
14116 */
14117ol.functions.FALSE = function() {
14118 return false;
14119};
14120
14121goog.provide('ol.geom.Geometry');
14122
14123goog.require('ol');
14124goog.require('ol.Object');
14125goog.require('ol.extent');
14126goog.require('ol.functions');
14127goog.require('ol.proj');
14128
14129
14130/**
14131 * @classdesc
14132 * Abstract base class; normally only used for creating subclasses and not
14133 * instantiated in apps.
14134 * Base class for vector geometries.
14135 *
14136 * To get notified of changes to the geometry, register a listener for the
14137 * generic `change` event on your geometry instance.
14138 *
14139 * @constructor
14140 * @abstract
14141 * @extends {ol.Object}
14142 * @api
14143 */
14144ol.geom.Geometry = function() {
14145
14146 ol.Object.call(this);
14147
14148 /**
14149 * @private
14150 * @type {ol.Extent}
14151 */
14152 this.extent_ = ol.extent.createEmpty();
14153
14154 /**
14155 * @private
14156 * @type {number}
14157 */
14158 this.extentRevision_ = -1;
14159
14160 /**
14161 * @protected
14162 * @type {Object.<string, ol.geom.Geometry>}
14163 */
14164 this.simplifiedGeometryCache = {};
14165
14166 /**
14167 * @protected
14168 * @type {number}
14169 */
14170 this.simplifiedGeometryMaxMinSquaredTolerance = 0;
14171
14172 /**
14173 * @protected
14174 * @type {number}
14175 */
14176 this.simplifiedGeometryRevision = 0;
14177
14178};
14179ol.inherits(ol.geom.Geometry, ol.Object);
14180
14181
14182/**
14183 * Make a complete copy of the geometry.
14184 * @abstract
14185 * @return {!ol.geom.Geometry} Clone.
14186 */
14187ol.geom.Geometry.prototype.clone = function() {};
14188
14189
14190/**
14191 * @abstract
14192 * @param {number} x X.
14193 * @param {number} y Y.
14194 * @param {ol.Coordinate} closestPoint Closest point.
14195 * @param {number} minSquaredDistance Minimum squared distance.
14196 * @return {number} Minimum squared distance.
14197 */
14198ol.geom.Geometry.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {};
14199
14200
14201/**
14202 * Return the closest point of the geometry to the passed point as
14203 * {@link ol.Coordinate coordinate}.
14204 * @param {ol.Coordinate} point Point.
14205 * @param {ol.Coordinate=} opt_closestPoint Closest point.
14206 * @return {ol.Coordinate} Closest point.
14207 * @api
14208 */
14209ol.geom.Geometry.prototype.getClosestPoint = function(point, opt_closestPoint) {
14210 var closestPoint = opt_closestPoint ? opt_closestPoint : [NaN, NaN];
14211 this.closestPointXY(point[0], point[1], closestPoint, Infinity);
14212 return closestPoint;
14213};
14214
14215
14216/**
14217 * Returns true if this geometry includes the specified coordinate. If the
14218 * coordinate is on the boundary of the geometry, returns false.
14219 * @param {ol.Coordinate} coordinate Coordinate.
14220 * @return {boolean} Contains coordinate.
14221 * @api
14222 */
14223ol.geom.Geometry.prototype.intersectsCoordinate = function(coordinate) {
14224 return this.containsXY(coordinate[0], coordinate[1]);
14225};
14226
14227
14228/**
14229 * @abstract
14230 * @param {ol.Extent} extent Extent.
14231 * @protected
14232 * @return {ol.Extent} extent Extent.
14233 */
14234ol.geom.Geometry.prototype.computeExtent = function(extent) {};
14235
14236
14237/**
14238 * @param {number} x X.
14239 * @param {number} y Y.
14240 * @return {boolean} Contains (x, y).
14241 */
14242ol.geom.Geometry.prototype.containsXY = ol.functions.FALSE;
14243
14244
14245/**
14246 * Get the extent of the geometry.
14247 * @param {ol.Extent=} opt_extent Extent.
14248 * @return {ol.Extent} extent Extent.
14249 * @api
14250 */
14251ol.geom.Geometry.prototype.getExtent = function(opt_extent) {
14252 if (this.extentRevision_ != this.getRevision()) {
14253 this.extent_ = this.computeExtent(this.extent_);
14254 this.extentRevision_ = this.getRevision();
14255 }
14256 return ol.extent.returnOrUpdate(this.extent_, opt_extent);
14257};
14258
14259
14260/**
14261 * Rotate the geometry around a given coordinate. This modifies the geometry
14262 * coordinates in place.
14263 * @abstract
14264 * @param {number} angle Rotation angle in radians.
14265 * @param {ol.Coordinate} anchor The rotation center.
14266 * @api
14267 */
14268ol.geom.Geometry.prototype.rotate = function(angle, anchor) {};
14269
14270
14271/**
14272 * Scale the geometry (with an optional origin). This modifies the geometry
14273 * coordinates in place.
14274 * @abstract
14275 * @param {number} sx The scaling factor in the x-direction.
14276 * @param {number=} opt_sy The scaling factor in the y-direction (defaults to
14277 * sx).
14278 * @param {ol.Coordinate=} opt_anchor The scale origin (defaults to the center
14279 * of the geometry extent).
14280 * @api
14281 */
14282ol.geom.Geometry.prototype.scale = function(sx, opt_sy, opt_anchor) {};
14283
14284
14285/**
14286 * Create a simplified version of this geometry. For linestrings, this uses
14287 * the the {@link
14288 * https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
14289 * Douglas Peucker} algorithm. For polygons, a quantization-based
14290 * simplification is used to preserve topology.
14291 * @function
14292 * @param {number} tolerance The tolerance distance for simplification.
14293 * @return {ol.geom.Geometry} A new, simplified version of the original
14294 * geometry.
14295 * @api
14296 */
14297ol.geom.Geometry.prototype.simplify = function(tolerance) {
14298 return this.getSimplifiedGeometry(tolerance * tolerance);
14299};
14300
14301
14302/**
14303 * Create a simplified version of this geometry using the Douglas Peucker
14304 * algorithm.
14305 * @see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
14306 * @abstract
14307 * @param {number} squaredTolerance Squared tolerance.
14308 * @return {ol.geom.Geometry} Simplified geometry.
14309 */
14310ol.geom.Geometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {};
14311
14312
14313/**
14314 * Get the type of this geometry.
14315 * @abstract
14316 * @return {ol.geom.GeometryType} Geometry type.
14317 */
14318ol.geom.Geometry.prototype.getType = function() {};
14319
14320
14321/**
14322 * Apply a transform function to each coordinate of the geometry.
14323 * The geometry is modified in place.
14324 * If you do not want the geometry modified in place, first `clone()` it and
14325 * then use this function on the clone.
14326 * @abstract
14327 * @param {ol.TransformFunction} transformFn Transform.
14328 */
14329ol.geom.Geometry.prototype.applyTransform = function(transformFn) {};
14330
14331
14332/**
14333 * Test if the geometry and the passed extent intersect.
14334 * @abstract
14335 * @param {ol.Extent} extent Extent.
14336 * @return {boolean} `true` if the geometry and the extent intersect.
14337 */
14338ol.geom.Geometry.prototype.intersectsExtent = function(extent) {};
14339
14340
14341/**
14342 * Translate the geometry. This modifies the geometry coordinates in place. If
14343 * instead you want a new geometry, first `clone()` this geometry.
14344 * @abstract
14345 * @param {number} deltaX Delta X.
14346 * @param {number} deltaY Delta Y.
14347 */
14348ol.geom.Geometry.prototype.translate = function(deltaX, deltaY) {};
14349
14350
14351/**
14352 * Transform each coordinate of the geometry from one coordinate reference
14353 * system to another. The geometry is modified in place.
14354 * For example, a line will be transformed to a line and a circle to a circle.
14355 * If you do not want the geometry modified in place, first `clone()` it and
14356 * then use this function on the clone.
14357 *
14358 * @param {ol.ProjectionLike} source The current projection. Can be a
14359 * string identifier or a {@link ol.proj.Projection} object.
14360 * @param {ol.ProjectionLike} destination The desired projection. Can be a
14361 * string identifier or a {@link ol.proj.Projection} object.
14362 * @return {ol.geom.Geometry} This geometry. Note that original geometry is
14363 * modified in place.
14364 * @api
14365 */
14366ol.geom.Geometry.prototype.transform = function(source, destination) {
14367 this.applyTransform(ol.proj.getTransform(source, destination));
14368 return this;
14369};
14370
14371goog.provide('ol.geom.flat.transform');
14372
14373
14374/**
14375 * @param {Array.<number>} flatCoordinates Flat coordinates.
14376 * @param {number} offset Offset.
14377 * @param {number} end End.
14378 * @param {number} stride Stride.
14379 * @param {ol.Transform} transform Transform.
14380 * @param {Array.<number>=} opt_dest Destination.
14381 * @return {Array.<number>} Transformed coordinates.
14382 */
14383ol.geom.flat.transform.transform2D = function(flatCoordinates, offset, end, stride, transform, opt_dest) {
14384 var dest = opt_dest ? opt_dest : [];
14385 var i = 0;
14386 var j;
14387 for (j = offset; j < end; j += stride) {
14388 var x = flatCoordinates[j];
14389 var y = flatCoordinates[j + 1];
14390 dest[i++] = transform[0] * x + transform[2] * y + transform[4];
14391 dest[i++] = transform[1] * x + transform[3] * y + transform[5];
14392 }
14393 if (opt_dest && dest.length != i) {
14394 dest.length = i;
14395 }
14396 return dest;
14397};
14398
14399
14400/**
14401 * @param {Array.<number>} flatCoordinates Flat coordinates.
14402 * @param {number} offset Offset.
14403 * @param {number} end End.
14404 * @param {number} stride Stride.
14405 * @param {number} angle Angle.
14406 * @param {Array.<number>} anchor Rotation anchor point.
14407 * @param {Array.<number>=} opt_dest Destination.
14408 * @return {Array.<number>} Transformed coordinates.
14409 */
14410ol.geom.flat.transform.rotate = function(flatCoordinates, offset, end, stride, angle, anchor, opt_dest) {
14411 var dest = opt_dest ? opt_dest : [];
14412 var cos = Math.cos(angle);
14413 var sin = Math.sin(angle);
14414 var anchorX = anchor[0];
14415 var anchorY = anchor[1];
14416 var i = 0;
14417 for (var j = offset; j < end; j += stride) {
14418 var deltaX = flatCoordinates[j] - anchorX;
14419 var deltaY = flatCoordinates[j + 1] - anchorY;
14420 dest[i++] = anchorX + deltaX * cos - deltaY * sin;
14421 dest[i++] = anchorY + deltaX * sin + deltaY * cos;
14422 for (var k = j + 2; k < j + stride; ++k) {
14423 dest[i++] = flatCoordinates[k];
14424 }
14425 }
14426 if (opt_dest && dest.length != i) {
14427 dest.length = i;
14428 }
14429 return dest;
14430};
14431
14432
14433/**
14434 * Scale the coordinates.
14435 * @param {Array.<number>} flatCoordinates Flat coordinates.
14436 * @param {number} offset Offset.
14437 * @param {number} end End.
14438 * @param {number} stride Stride.
14439 * @param {number} sx Scale factor in the x-direction.
14440 * @param {number} sy Scale factor in the y-direction.
14441 * @param {Array.<number>} anchor Scale anchor point.
14442 * @param {Array.<number>=} opt_dest Destination.
14443 * @return {Array.<number>} Transformed coordinates.
14444 */
14445ol.geom.flat.transform.scale = function(flatCoordinates, offset, end, stride, sx, sy, anchor, opt_dest) {
14446 var dest = opt_dest ? opt_dest : [];
14447 var anchorX = anchor[0];
14448 var anchorY = anchor[1];
14449 var i = 0;
14450 for (var j = offset; j < end; j += stride) {
14451 var deltaX = flatCoordinates[j] - anchorX;
14452 var deltaY = flatCoordinates[j + 1] - anchorY;
14453 dest[i++] = anchorX + sx * deltaX;
14454 dest[i++] = anchorY + sy * deltaY;
14455 for (var k = j + 2; k < j + stride; ++k) {
14456 dest[i++] = flatCoordinates[k];
14457 }
14458 }
14459 if (opt_dest && dest.length != i) {
14460 dest.length = i;
14461 }
14462 return dest;
14463};
14464
14465
14466/**
14467 * @param {Array.<number>} flatCoordinates Flat coordinates.
14468 * @param {number} offset Offset.
14469 * @param {number} end End.
14470 * @param {number} stride Stride.
14471 * @param {number} deltaX Delta X.
14472 * @param {number} deltaY Delta Y.
14473 * @param {Array.<number>=} opt_dest Destination.
14474 * @return {Array.<number>} Transformed coordinates.
14475 */
14476ol.geom.flat.transform.translate = function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) {
14477 var dest = opt_dest ? opt_dest : [];
14478 var i = 0;
14479 var j, k;
14480 for (j = offset; j < end; j += stride) {
14481 dest[i++] = flatCoordinates[j] + deltaX;
14482 dest[i++] = flatCoordinates[j + 1] + deltaY;
14483 for (k = j + 2; k < j + stride; ++k) {
14484 dest[i++] = flatCoordinates[k];
14485 }
14486 }
14487 if (opt_dest && dest.length != i) {
14488 dest.length = i;
14489 }
14490 return dest;
14491};
14492
14493goog.provide('ol.geom.SimpleGeometry');
14494
14495goog.require('ol');
14496goog.require('ol.functions');
14497goog.require('ol.extent');
14498goog.require('ol.geom.Geometry');
14499goog.require('ol.geom.GeometryLayout');
14500goog.require('ol.geom.flat.transform');
14501goog.require('ol.obj');
14502
14503
14504/**
14505 * @classdesc
14506 * Abstract base class; only used for creating subclasses; do not instantiate
14507 * in apps, as cannot be rendered.
14508 *
14509 * @constructor
14510 * @abstract
14511 * @extends {ol.geom.Geometry}
14512 * @api
14513 */
14514ol.geom.SimpleGeometry = function() {
14515
14516 ol.geom.Geometry.call(this);
14517
14518 /**
14519 * @protected
14520 * @type {ol.geom.GeometryLayout}
14521 */
14522 this.layout = ol.geom.GeometryLayout.XY;
14523
14524 /**
14525 * @protected
14526 * @type {number}
14527 */
14528 this.stride = 2;
14529
14530 /**
14531 * @protected
14532 * @type {Array.<number>}
14533 */
14534 this.flatCoordinates = null;
14535
14536};
14537ol.inherits(ol.geom.SimpleGeometry, ol.geom.Geometry);
14538
14539
14540/**
14541 * @param {number} stride Stride.
14542 * @private
14543 * @return {ol.geom.GeometryLayout} layout Layout.
14544 */
14545ol.geom.SimpleGeometry.getLayoutForStride_ = function(stride) {
14546 var layout;
14547 if (stride == 2) {
14548 layout = ol.geom.GeometryLayout.XY;
14549 } else if (stride == 3) {
14550 layout = ol.geom.GeometryLayout.XYZ;
14551 } else if (stride == 4) {
14552 layout = ol.geom.GeometryLayout.XYZM;
14553 }
14554 return /** @type {ol.geom.GeometryLayout} */ (layout);
14555};
14556
14557
14558/**
14559 * @param {ol.geom.GeometryLayout} layout Layout.
14560 * @return {number} Stride.
14561 */
14562ol.geom.SimpleGeometry.getStrideForLayout = function(layout) {
14563 var stride;
14564 if (layout == ol.geom.GeometryLayout.XY) {
14565 stride = 2;
14566 } else if (layout == ol.geom.GeometryLayout.XYZ || layout == ol.geom.GeometryLayout.XYM) {
14567 stride = 3;
14568 } else if (layout == ol.geom.GeometryLayout.XYZM) {
14569 stride = 4;
14570 }
14571 return /** @type {number} */ (stride);
14572};
14573
14574
14575/**
14576 * @inheritDoc
14577 */
14578ol.geom.SimpleGeometry.prototype.containsXY = ol.functions.FALSE;
14579
14580
14581/**
14582 * @inheritDoc
14583 */
14584ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) {
14585 return ol.extent.createOrUpdateFromFlatCoordinates(
14586 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
14587 extent);
14588};
14589
14590
14591/**
14592 * @abstract
14593 * @return {Array} Coordinates.
14594 */
14595ol.geom.SimpleGeometry.prototype.getCoordinates = function() {};
14596
14597
14598/**
14599 * Return the first coordinate of the geometry.
14600 * @return {ol.Coordinate} First coordinate.
14601 * @api
14602 */
14603ol.geom.SimpleGeometry.prototype.getFirstCoordinate = function() {
14604 return this.flatCoordinates.slice(0, this.stride);
14605};
14606
14607
14608/**
14609 * @return {Array.<number>} Flat coordinates.
14610 */
14611ol.geom.SimpleGeometry.prototype.getFlatCoordinates = function() {
14612 return this.flatCoordinates;
14613};
14614
14615
14616/**
14617 * Return the last coordinate of the geometry.
14618 * @return {ol.Coordinate} Last point.
14619 * @api
14620 */
14621ol.geom.SimpleGeometry.prototype.getLastCoordinate = function() {
14622 return this.flatCoordinates.slice(this.flatCoordinates.length - this.stride);
14623};
14624
14625
14626/**
14627 * Return the {@link ol.geom.GeometryLayout layout} of the geometry.
14628 * @return {ol.geom.GeometryLayout} Layout.
14629 * @api
14630 */
14631ol.geom.SimpleGeometry.prototype.getLayout = function() {
14632 return this.layout;
14633};
14634
14635
14636/**
14637 * @inheritDoc
14638 */
14639ol.geom.SimpleGeometry.prototype.getSimplifiedGeometry = function(squaredTolerance) {
14640 if (this.simplifiedGeometryRevision != this.getRevision()) {
14641 ol.obj.clear(this.simplifiedGeometryCache);
14642 this.simplifiedGeometryMaxMinSquaredTolerance = 0;
14643 this.simplifiedGeometryRevision = this.getRevision();
14644 }
14645 // If squaredTolerance is negative or if we know that simplification will not
14646 // have any effect then just return this.
14647 if (squaredTolerance < 0 ||
14648 (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
14649 squaredTolerance <= this.simplifiedGeometryMaxMinSquaredTolerance)) {
14650 return this;
14651 }
14652 var key = squaredTolerance.toString();
14653 if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
14654 return this.simplifiedGeometryCache[key];
14655 } else {
14656 var simplifiedGeometry =
14657 this.getSimplifiedGeometryInternal(squaredTolerance);
14658 var simplifiedFlatCoordinates = simplifiedGeometry.getFlatCoordinates();
14659 if (simplifiedFlatCoordinates.length < this.flatCoordinates.length) {
14660 this.simplifiedGeometryCache[key] = simplifiedGeometry;
14661 return simplifiedGeometry;
14662 } else {
14663 // Simplification did not actually remove any coordinates. We now know
14664 // that any calls to getSimplifiedGeometry with a squaredTolerance less
14665 // than or equal to the current squaredTolerance will also not have any
14666 // effect. This allows us to short circuit simplification (saving CPU
14667 // cycles) and prevents the cache of simplified geometries from filling
14668 // up with useless identical copies of this geometry (saving memory).
14669 this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
14670 return this;
14671 }
14672 }
14673};
14674
14675
14676/**
14677 * @param {number} squaredTolerance Squared tolerance.
14678 * @return {ol.geom.SimpleGeometry} Simplified geometry.
14679 * @protected
14680 */
14681ol.geom.SimpleGeometry.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
14682 return this;
14683};
14684
14685
14686/**
14687 * @return {number} Stride.
14688 */
14689ol.geom.SimpleGeometry.prototype.getStride = function() {
14690 return this.stride;
14691};
14692
14693
14694/**
14695 * @param {ol.geom.GeometryLayout} layout Layout.
14696 * @param {Array.<number>} flatCoordinates Flat coordinates.
14697 * @protected
14698 */
14699ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal = function(layout, flatCoordinates) {
14700 this.stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);
14701 this.layout = layout;
14702 this.flatCoordinates = flatCoordinates;
14703};
14704
14705
14706/**
14707 * @abstract
14708 * @param {Array} coordinates Coordinates.
14709 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
14710 */
14711ol.geom.SimpleGeometry.prototype.setCoordinates = function(coordinates, opt_layout) {};
14712
14713
14714/**
14715 * @param {ol.geom.GeometryLayout|undefined} layout Layout.
14716 * @param {Array} coordinates Coordinates.
14717 * @param {number} nesting Nesting.
14718 * @protected
14719 */
14720ol.geom.SimpleGeometry.prototype.setLayout = function(layout, coordinates, nesting) {
14721 /** @type {number} */
14722 var stride;
14723 if (layout) {
14724 stride = ol.geom.SimpleGeometry.getStrideForLayout(layout);
14725 } else {
14726 var i;
14727 for (i = 0; i < nesting; ++i) {
14728 if (coordinates.length === 0) {
14729 this.layout = ol.geom.GeometryLayout.XY;
14730 this.stride = 2;
14731 return;
14732 } else {
14733 coordinates = /** @type {Array} */ (coordinates[0]);
14734 }
14735 }
14736 stride = coordinates.length;
14737 layout = ol.geom.SimpleGeometry.getLayoutForStride_(stride);
14738 }
14739 this.layout = layout;
14740 this.stride = stride;
14741};
14742
14743
14744/**
14745 * @inheritDoc
14746 * @api
14747 */
14748ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) {
14749 if (this.flatCoordinates) {
14750 transformFn(this.flatCoordinates, this.flatCoordinates, this.stride);
14751 this.changed();
14752 }
14753};
14754
14755
14756/**
14757 * @inheritDoc
14758 * @api
14759 */
14760ol.geom.SimpleGeometry.prototype.rotate = function(angle, anchor) {
14761 var flatCoordinates = this.getFlatCoordinates();
14762 if (flatCoordinates) {
14763 var stride = this.getStride();
14764 ol.geom.flat.transform.rotate(
14765 flatCoordinates, 0, flatCoordinates.length,
14766 stride, angle, anchor, flatCoordinates);
14767 this.changed();
14768 }
14769};
14770
14771
14772/**
14773 * @inheritDoc
14774 * @api
14775 */
14776ol.geom.SimpleGeometry.prototype.scale = function(sx, opt_sy, opt_anchor) {
14777 var sy = opt_sy;
14778 if (sy === undefined) {
14779 sy = sx;
14780 }
14781 var anchor = opt_anchor;
14782 if (!anchor) {
14783 anchor = ol.extent.getCenter(this.getExtent());
14784 }
14785 var flatCoordinates = this.getFlatCoordinates();
14786 if (flatCoordinates) {
14787 var stride = this.getStride();
14788 ol.geom.flat.transform.scale(
14789 flatCoordinates, 0, flatCoordinates.length,
14790 stride, sx, sy, anchor, flatCoordinates);
14791 this.changed();
14792 }
14793};
14794
14795
14796/**
14797 * @inheritDoc
14798 * @api
14799 */
14800ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) {
14801 var flatCoordinates = this.getFlatCoordinates();
14802 if (flatCoordinates) {
14803 var stride = this.getStride();
14804 ol.geom.flat.transform.translate(
14805 flatCoordinates, 0, flatCoordinates.length, stride,
14806 deltaX, deltaY, flatCoordinates);
14807 this.changed();
14808 }
14809};
14810
14811
14812/**
14813 * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry.
14814 * @param {ol.Transform} transform Transform.
14815 * @param {Array.<number>=} opt_dest Destination.
14816 * @return {Array.<number>} Transformed flat coordinates.
14817 */
14818ol.geom.SimpleGeometry.transform2D = function(simpleGeometry, transform, opt_dest) {
14819 var flatCoordinates = simpleGeometry.getFlatCoordinates();
14820 if (!flatCoordinates) {
14821 return null;
14822 } else {
14823 var stride = simpleGeometry.getStride();
14824 return ol.geom.flat.transform.transform2D(
14825 flatCoordinates, 0, flatCoordinates.length, stride,
14826 transform, opt_dest);
14827 }
14828};
14829
14830goog.provide('ol.geom.flat.area');
14831
14832
14833/**
14834 * @param {Array.<number>} flatCoordinates Flat coordinates.
14835 * @param {number} offset Offset.
14836 * @param {number} end End.
14837 * @param {number} stride Stride.
14838 * @return {number} Area.
14839 */
14840ol.geom.flat.area.linearRing = function(flatCoordinates, offset, end, stride) {
14841 var twiceArea = 0;
14842 var x1 = flatCoordinates[end - stride];
14843 var y1 = flatCoordinates[end - stride + 1];
14844 for (; offset < end; offset += stride) {
14845 var x2 = flatCoordinates[offset];
14846 var y2 = flatCoordinates[offset + 1];
14847 twiceArea += y1 * x2 - x1 * y2;
14848 x1 = x2;
14849 y1 = y2;
14850 }
14851 return twiceArea / 2;
14852};
14853
14854
14855/**
14856 * @param {Array.<number>} flatCoordinates Flat coordinates.
14857 * @param {number} offset Offset.
14858 * @param {Array.<number>} ends Ends.
14859 * @param {number} stride Stride.
14860 * @return {number} Area.
14861 */
14862ol.geom.flat.area.linearRings = function(flatCoordinates, offset, ends, stride) {
14863 var area = 0;
14864 var i, ii;
14865 for (i = 0, ii = ends.length; i < ii; ++i) {
14866 var end = ends[i];
14867 area += ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);
14868 offset = end;
14869 }
14870 return area;
14871};
14872
14873
14874/**
14875 * @param {Array.<number>} flatCoordinates Flat coordinates.
14876 * @param {number} offset Offset.
14877 * @param {Array.<Array.<number>>} endss Endss.
14878 * @param {number} stride Stride.
14879 * @return {number} Area.
14880 */
14881ol.geom.flat.area.linearRingss = function(flatCoordinates, offset, endss, stride) {
14882 var area = 0;
14883 var i, ii;
14884 for (i = 0, ii = endss.length; i < ii; ++i) {
14885 var ends = endss[i];
14886 area +=
14887 ol.geom.flat.area.linearRings(flatCoordinates, offset, ends, stride);
14888 offset = ends[ends.length - 1];
14889 }
14890 return area;
14891};
14892
14893goog.provide('ol.geom.flat.closest');
14894
14895goog.require('ol.math');
14896
14897
14898/**
14899 * Returns the point on the 2D line segment flatCoordinates[offset1] to
14900 * flatCoordinates[offset2] that is closest to the point (x, y). Extra
14901 * dimensions are linearly interpolated.
14902 * @param {Array.<number>} flatCoordinates Flat coordinates.
14903 * @param {number} offset1 Offset 1.
14904 * @param {number} offset2 Offset 2.
14905 * @param {number} stride Stride.
14906 * @param {number} x X.
14907 * @param {number} y Y.
14908 * @param {Array.<number>} closestPoint Closest point.
14909 */
14910ol.geom.flat.closest.point = function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
14911 var x1 = flatCoordinates[offset1];
14912 var y1 = flatCoordinates[offset1 + 1];
14913 var dx = flatCoordinates[offset2] - x1;
14914 var dy = flatCoordinates[offset2 + 1] - y1;
14915 var i, offset;
14916 if (dx === 0 && dy === 0) {
14917 offset = offset1;
14918 } else {
14919 var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
14920 if (t > 1) {
14921 offset = offset2;
14922 } else if (t > 0) {
14923 for (i = 0; i < stride; ++i) {
14924 closestPoint[i] = ol.math.lerp(flatCoordinates[offset1 + i],
14925 flatCoordinates[offset2 + i], t);
14926 }
14927 closestPoint.length = stride;
14928 return;
14929 } else {
14930 offset = offset1;
14931 }
14932 }
14933 for (i = 0; i < stride; ++i) {
14934 closestPoint[i] = flatCoordinates[offset + i];
14935 }
14936 closestPoint.length = stride;
14937};
14938
14939
14940/**
14941 * Return the squared of the largest distance between any pair of consecutive
14942 * coordinates.
14943 * @param {Array.<number>} flatCoordinates Flat coordinates.
14944 * @param {number} offset Offset.
14945 * @param {number} end End.
14946 * @param {number} stride Stride.
14947 * @param {number} maxSquaredDelta Max squared delta.
14948 * @return {number} Max squared delta.
14949 */
14950ol.geom.flat.closest.getMaxSquaredDelta = function(flatCoordinates, offset, end, stride, maxSquaredDelta) {
14951 var x1 = flatCoordinates[offset];
14952 var y1 = flatCoordinates[offset + 1];
14953 for (offset += stride; offset < end; offset += stride) {
14954 var x2 = flatCoordinates[offset];
14955 var y2 = flatCoordinates[offset + 1];
14956 var squaredDelta = ol.math.squaredDistance(x1, y1, x2, y2);
14957 if (squaredDelta > maxSquaredDelta) {
14958 maxSquaredDelta = squaredDelta;
14959 }
14960 x1 = x2;
14961 y1 = y2;
14962 }
14963 return maxSquaredDelta;
14964};
14965
14966
14967/**
14968 * @param {Array.<number>} flatCoordinates Flat coordinates.
14969 * @param {number} offset Offset.
14970 * @param {Array.<number>} ends Ends.
14971 * @param {number} stride Stride.
14972 * @param {number} maxSquaredDelta Max squared delta.
14973 * @return {number} Max squared delta.
14974 */
14975ol.geom.flat.closest.getsMaxSquaredDelta = function(flatCoordinates, offset, ends, stride, maxSquaredDelta) {
14976 var i, ii;
14977 for (i = 0, ii = ends.length; i < ii; ++i) {
14978 var end = ends[i];
14979 maxSquaredDelta = ol.geom.flat.closest.getMaxSquaredDelta(
14980 flatCoordinates, offset, end, stride, maxSquaredDelta);
14981 offset = end;
14982 }
14983 return maxSquaredDelta;
14984};
14985
14986
14987/**
14988 * @param {Array.<number>} flatCoordinates Flat coordinates.
14989 * @param {number} offset Offset.
14990 * @param {Array.<Array.<number>>} endss Endss.
14991 * @param {number} stride Stride.
14992 * @param {number} maxSquaredDelta Max squared delta.
14993 * @return {number} Max squared delta.
14994 */
14995ol.geom.flat.closest.getssMaxSquaredDelta = function(flatCoordinates, offset, endss, stride, maxSquaredDelta) {
14996 var i, ii;
14997 for (i = 0, ii = endss.length; i < ii; ++i) {
14998 var ends = endss[i];
14999 maxSquaredDelta = ol.geom.flat.closest.getsMaxSquaredDelta(
15000 flatCoordinates, offset, ends, stride, maxSquaredDelta);
15001 offset = ends[ends.length - 1];
15002 }
15003 return maxSquaredDelta;
15004};
15005
15006
15007/**
15008 * @param {Array.<number>} flatCoordinates Flat coordinates.
15009 * @param {number} offset Offset.
15010 * @param {number} end End.
15011 * @param {number} stride Stride.
15012 * @param {number} maxDelta Max delta.
15013 * @param {boolean} isRing Is ring.
15014 * @param {number} x X.
15015 * @param {number} y Y.
15016 * @param {Array.<number>} closestPoint Closest point.
15017 * @param {number} minSquaredDistance Minimum squared distance.
15018 * @param {Array.<number>=} opt_tmpPoint Temporary point object.
15019 * @return {number} Minimum squared distance.
15020 */
15021ol.geom.flat.closest.getClosestPoint = function(flatCoordinates, offset, end,
15022 stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
15023 opt_tmpPoint) {
15024 if (offset == end) {
15025 return minSquaredDistance;
15026 }
15027 var i, squaredDistance;
15028 if (maxDelta === 0) {
15029 // All points are identical, so just test the first point.
15030 squaredDistance = ol.math.squaredDistance(
15031 x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);
15032 if (squaredDistance < minSquaredDistance) {
15033 for (i = 0; i < stride; ++i) {
15034 closestPoint[i] = flatCoordinates[offset + i];
15035 }
15036 closestPoint.length = stride;
15037 return squaredDistance;
15038 } else {
15039 return minSquaredDistance;
15040 }
15041 }
15042 var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
15043 var index = offset + stride;
15044 while (index < end) {
15045 ol.geom.flat.closest.point(
15046 flatCoordinates, index - stride, index, stride, x, y, tmpPoint);
15047 squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
15048 if (squaredDistance < minSquaredDistance) {
15049 minSquaredDistance = squaredDistance;
15050 for (i = 0; i < stride; ++i) {
15051 closestPoint[i] = tmpPoint[i];
15052 }
15053 closestPoint.length = stride;
15054 index += stride;
15055 } else {
15056 // Skip ahead multiple points, because we know that all the skipped
15057 // points cannot be any closer than the closest point we have found so
15058 // far. We know this because we know how close the current point is, how
15059 // close the closest point we have found so far is, and the maximum
15060 // distance between consecutive points. For example, if we're currently
15061 // at distance 10, the best we've found so far is 3, and that the maximum
15062 // distance between consecutive points is 2, then we'll need to skip at
15063 // least (10 - 3) / 2 == 3 (rounded down) points to have any chance of
15064 // finding a closer point. We use Math.max(..., 1) to ensure that we
15065 // always advance at least one point, to avoid an infinite loop.
15066 index += stride * Math.max(
15067 ((Math.sqrt(squaredDistance) -
15068 Math.sqrt(minSquaredDistance)) / maxDelta) | 0, 1);
15069 }
15070 }
15071 if (isRing) {
15072 // Check the closing segment.
15073 ol.geom.flat.closest.point(
15074 flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);
15075 squaredDistance = ol.math.squaredDistance(x, y, tmpPoint[0], tmpPoint[1]);
15076 if (squaredDistance < minSquaredDistance) {
15077 minSquaredDistance = squaredDistance;
15078 for (i = 0; i < stride; ++i) {
15079 closestPoint[i] = tmpPoint[i];
15080 }
15081 closestPoint.length = stride;
15082 }
15083 }
15084 return minSquaredDistance;
15085};
15086
15087
15088/**
15089 * @param {Array.<number>} flatCoordinates Flat coordinates.
15090 * @param {number} offset Offset.
15091 * @param {Array.<number>} ends Ends.
15092 * @param {number} stride Stride.
15093 * @param {number} maxDelta Max delta.
15094 * @param {boolean} isRing Is ring.
15095 * @param {number} x X.
15096 * @param {number} y Y.
15097 * @param {Array.<number>} closestPoint Closest point.
15098 * @param {number} minSquaredDistance Minimum squared distance.
15099 * @param {Array.<number>=} opt_tmpPoint Temporary point object.
15100 * @return {number} Minimum squared distance.
15101 */
15102ol.geom.flat.closest.getsClosestPoint = function(flatCoordinates, offset, ends,
15103 stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
15104 opt_tmpPoint) {
15105 var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
15106 var i, ii;
15107 for (i = 0, ii = ends.length; i < ii; ++i) {
15108 var end = ends[i];
15109 minSquaredDistance = ol.geom.flat.closest.getClosestPoint(
15110 flatCoordinates, offset, end, stride,
15111 maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
15112 offset = end;
15113 }
15114 return minSquaredDistance;
15115};
15116
15117
15118/**
15119 * @param {Array.<number>} flatCoordinates Flat coordinates.
15120 * @param {number} offset Offset.
15121 * @param {Array.<Array.<number>>} endss Endss.
15122 * @param {number} stride Stride.
15123 * @param {number} maxDelta Max delta.
15124 * @param {boolean} isRing Is ring.
15125 * @param {number} x X.
15126 * @param {number} y Y.
15127 * @param {Array.<number>} closestPoint Closest point.
15128 * @param {number} minSquaredDistance Minimum squared distance.
15129 * @param {Array.<number>=} opt_tmpPoint Temporary point object.
15130 * @return {number} Minimum squared distance.
15131 */
15132ol.geom.flat.closest.getssClosestPoint = function(flatCoordinates, offset,
15133 endss, stride, maxDelta, isRing, x, y, closestPoint, minSquaredDistance,
15134 opt_tmpPoint) {
15135 var tmpPoint = opt_tmpPoint ? opt_tmpPoint : [NaN, NaN];
15136 var i, ii;
15137 for (i = 0, ii = endss.length; i < ii; ++i) {
15138 var ends = endss[i];
15139 minSquaredDistance = ol.geom.flat.closest.getsClosestPoint(
15140 flatCoordinates, offset, ends, stride,
15141 maxDelta, isRing, x, y, closestPoint, minSquaredDistance, tmpPoint);
15142 offset = ends[ends.length - 1];
15143 }
15144 return minSquaredDistance;
15145};
15146
15147goog.provide('ol.geom.flat.deflate');
15148
15149
15150/**
15151 * @param {Array.<number>} flatCoordinates Flat coordinates.
15152 * @param {number} offset Offset.
15153 * @param {ol.Coordinate} coordinate Coordinate.
15154 * @param {number} stride Stride.
15155 * @return {number} offset Offset.
15156 */
15157ol.geom.flat.deflate.coordinate = function(flatCoordinates, offset, coordinate, stride) {
15158 var i, ii;
15159 for (i = 0, ii = coordinate.length; i < ii; ++i) {
15160 flatCoordinates[offset++] = coordinate[i];
15161 }
15162 return offset;
15163};
15164
15165
15166/**
15167 * @param {Array.<number>} flatCoordinates Flat coordinates.
15168 * @param {number} offset Offset.
15169 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
15170 * @param {number} stride Stride.
15171 * @return {number} offset Offset.
15172 */
15173ol.geom.flat.deflate.coordinates = function(flatCoordinates, offset, coordinates, stride) {
15174 var i, ii;
15175 for (i = 0, ii = coordinates.length; i < ii; ++i) {
15176 var coordinate = coordinates[i];
15177 var j;
15178 for (j = 0; j < stride; ++j) {
15179 flatCoordinates[offset++] = coordinate[j];
15180 }
15181 }
15182 return offset;
15183};
15184
15185
15186/**
15187 * @param {Array.<number>} flatCoordinates Flat coordinates.
15188 * @param {number} offset Offset.
15189 * @param {Array.<Array.<ol.Coordinate>>} coordinatess Coordinatess.
15190 * @param {number} stride Stride.
15191 * @param {Array.<number>=} opt_ends Ends.
15192 * @return {Array.<number>} Ends.
15193 */
15194ol.geom.flat.deflate.coordinatess = function(flatCoordinates, offset, coordinatess, stride, opt_ends) {
15195 var ends = opt_ends ? opt_ends : [];
15196 var i = 0;
15197 var j, jj;
15198 for (j = 0, jj = coordinatess.length; j < jj; ++j) {
15199 var end = ol.geom.flat.deflate.coordinates(
15200 flatCoordinates, offset, coordinatess[j], stride);
15201 ends[i++] = end;
15202 offset = end;
15203 }
15204 ends.length = i;
15205 return ends;
15206};
15207
15208
15209/**
15210 * @param {Array.<number>} flatCoordinates Flat coordinates.
15211 * @param {number} offset Offset.
15212 * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinatesss Coordinatesss.
15213 * @param {number} stride Stride.
15214 * @param {Array.<Array.<number>>=} opt_endss Endss.
15215 * @return {Array.<Array.<number>>} Endss.
15216 */
15217ol.geom.flat.deflate.coordinatesss = function(flatCoordinates, offset, coordinatesss, stride, opt_endss) {
15218 var endss = opt_endss ? opt_endss : [];
15219 var i = 0;
15220 var j, jj;
15221 for (j = 0, jj = coordinatesss.length; j < jj; ++j) {
15222 var ends = ol.geom.flat.deflate.coordinatess(
15223 flatCoordinates, offset, coordinatesss[j], stride, endss[i]);
15224 endss[i++] = ends;
15225 offset = ends[ends.length - 1];
15226 }
15227 endss.length = i;
15228 return endss;
15229};
15230
15231goog.provide('ol.geom.flat.inflate');
15232
15233
15234/**
15235 * @param {Array.<number>} flatCoordinates Flat coordinates.
15236 * @param {number} offset Offset.
15237 * @param {number} end End.
15238 * @param {number} stride Stride.
15239 * @param {Array.<ol.Coordinate>=} opt_coordinates Coordinates.
15240 * @return {Array.<ol.Coordinate>} Coordinates.
15241 */
15242ol.geom.flat.inflate.coordinates = function(flatCoordinates, offset, end, stride, opt_coordinates) {
15243 var coordinates = opt_coordinates !== undefined ? opt_coordinates : [];
15244 var i = 0;
15245 var j;
15246 for (j = offset; j < end; j += stride) {
15247 coordinates[i++] = flatCoordinates.slice(j, j + stride);
15248 }
15249 coordinates.length = i;
15250 return coordinates;
15251};
15252
15253
15254/**
15255 * @param {Array.<number>} flatCoordinates Flat coordinates.
15256 * @param {number} offset Offset.
15257 * @param {Array.<number>} ends Ends.
15258 * @param {number} stride Stride.
15259 * @param {Array.<Array.<ol.Coordinate>>=} opt_coordinatess Coordinatess.
15260 * @return {Array.<Array.<ol.Coordinate>>} Coordinatess.
15261 */
15262ol.geom.flat.inflate.coordinatess = function(flatCoordinates, offset, ends, stride, opt_coordinatess) {
15263 var coordinatess = opt_coordinatess !== undefined ? opt_coordinatess : [];
15264 var i = 0;
15265 var j, jj;
15266 for (j = 0, jj = ends.length; j < jj; ++j) {
15267 var end = ends[j];
15268 coordinatess[i++] = ol.geom.flat.inflate.coordinates(
15269 flatCoordinates, offset, end, stride, coordinatess[i]);
15270 offset = end;
15271 }
15272 coordinatess.length = i;
15273 return coordinatess;
15274};
15275
15276
15277/**
15278 * @param {Array.<number>} flatCoordinates Flat coordinates.
15279 * @param {number} offset Offset.
15280 * @param {Array.<Array.<number>>} endss Endss.
15281 * @param {number} stride Stride.
15282 * @param {Array.<Array.<Array.<ol.Coordinate>>>=} opt_coordinatesss
15283 * Coordinatesss.
15284 * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinatesss.
15285 */
15286ol.geom.flat.inflate.coordinatesss = function(flatCoordinates, offset, endss, stride, opt_coordinatesss) {
15287 var coordinatesss = opt_coordinatesss !== undefined ? opt_coordinatesss : [];
15288 var i = 0;
15289 var j, jj;
15290 for (j = 0, jj = endss.length; j < jj; ++j) {
15291 var ends = endss[j];
15292 coordinatesss[i++] = ol.geom.flat.inflate.coordinatess(
15293 flatCoordinates, offset, ends, stride, coordinatesss[i]);
15294 offset = ends[ends.length - 1];
15295 }
15296 coordinatesss.length = i;
15297 return coordinatesss;
15298};
15299
15300// Based on simplify-js https://github.com/mourner/simplify-js
15301// Copyright (c) 2012, Vladimir Agafonkin
15302// All rights reserved.
15303//
15304// Redistribution and use in source and binary forms, with or without
15305// modification, are permitted provided that the following conditions are met:
15306//
15307// 1. Redistributions of source code must retain the above copyright notice,
15308// this list of conditions and the following disclaimer.
15309//
15310// 2. Redistributions in binary form must reproduce the above copyright
15311// notice, this list of conditions and the following disclaimer in the
15312// documentation and/or other materials provided with the distribution.
15313//
15314// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15315// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15316// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15317// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
15318// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
15319// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
15320// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
15321// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
15322// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
15323// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
15324// POSSIBILITY OF SUCH DAMAGE.
15325
15326goog.provide('ol.geom.flat.simplify');
15327
15328goog.require('ol.math');
15329
15330
15331/**
15332 * @param {Array.<number>} flatCoordinates Flat coordinates.
15333 * @param {number} offset Offset.
15334 * @param {number} end End.
15335 * @param {number} stride Stride.
15336 * @param {number} squaredTolerance Squared tolerance.
15337 * @param {boolean} highQuality Highest quality.
15338 * @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat
15339 * coordinates.
15340 * @return {Array.<number>} Simplified line string.
15341 */
15342ol.geom.flat.simplify.lineString = function(flatCoordinates, offset, end,
15343 stride, squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {
15344 var simplifiedFlatCoordinates = opt_simplifiedFlatCoordinates !== undefined ?
15345 opt_simplifiedFlatCoordinates : [];
15346 if (!highQuality) {
15347 end = ol.geom.flat.simplify.radialDistance(flatCoordinates, offset, end,
15348 stride, squaredTolerance,
15349 simplifiedFlatCoordinates, 0);
15350 flatCoordinates = simplifiedFlatCoordinates;
15351 offset = 0;
15352 stride = 2;
15353 }
15354 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
15355 flatCoordinates, offset, end, stride, squaredTolerance,
15356 simplifiedFlatCoordinates, 0);
15357 return simplifiedFlatCoordinates;
15358};
15359
15360
15361/**
15362 * @param {Array.<number>} flatCoordinates Flat coordinates.
15363 * @param {number} offset Offset.
15364 * @param {number} end End.
15365 * @param {number} stride Stride.
15366 * @param {number} squaredTolerance Squared tolerance.
15367 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15368 * coordinates.
15369 * @param {number} simplifiedOffset Simplified offset.
15370 * @return {number} Simplified offset.
15371 */
15372ol.geom.flat.simplify.douglasPeucker = function(flatCoordinates, offset, end,
15373 stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
15374 var n = (end - offset) / stride;
15375 if (n < 3) {
15376 for (; offset < end; offset += stride) {
15377 simplifiedFlatCoordinates[simplifiedOffset++] =
15378 flatCoordinates[offset];
15379 simplifiedFlatCoordinates[simplifiedOffset++] =
15380 flatCoordinates[offset + 1];
15381 }
15382 return simplifiedOffset;
15383 }
15384 /** @type {Array.<number>} */
15385 var markers = new Array(n);
15386 markers[0] = 1;
15387 markers[n - 1] = 1;
15388 /** @type {Array.<number>} */
15389 var stack = [offset, end - stride];
15390 var index = 0;
15391 var i;
15392 while (stack.length > 0) {
15393 var last = stack.pop();
15394 var first = stack.pop();
15395 var maxSquaredDistance = 0;
15396 var x1 = flatCoordinates[first];
15397 var y1 = flatCoordinates[first + 1];
15398 var x2 = flatCoordinates[last];
15399 var y2 = flatCoordinates[last + 1];
15400 for (i = first + stride; i < last; i += stride) {
15401 var x = flatCoordinates[i];
15402 var y = flatCoordinates[i + 1];
15403 var squaredDistance = ol.math.squaredSegmentDistance(
15404 x, y, x1, y1, x2, y2);
15405 if (squaredDistance > maxSquaredDistance) {
15406 index = i;
15407 maxSquaredDistance = squaredDistance;
15408 }
15409 }
15410 if (maxSquaredDistance > squaredTolerance) {
15411 markers[(index - offset) / stride] = 1;
15412 if (first + stride < index) {
15413 stack.push(first, index);
15414 }
15415 if (index + stride < last) {
15416 stack.push(index, last);
15417 }
15418 }
15419 }
15420 for (i = 0; i < n; ++i) {
15421 if (markers[i]) {
15422 simplifiedFlatCoordinates[simplifiedOffset++] =
15423 flatCoordinates[offset + i * stride];
15424 simplifiedFlatCoordinates[simplifiedOffset++] =
15425 flatCoordinates[offset + i * stride + 1];
15426 }
15427 }
15428 return simplifiedOffset;
15429};
15430
15431
15432/**
15433 * @param {Array.<number>} flatCoordinates Flat coordinates.
15434 * @param {number} offset Offset.
15435 * @param {Array.<number>} ends Ends.
15436 * @param {number} stride Stride.
15437 * @param {number} squaredTolerance Squared tolerance.
15438 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15439 * coordinates.
15440 * @param {number} simplifiedOffset Simplified offset.
15441 * @param {Array.<number>} simplifiedEnds Simplified ends.
15442 * @return {number} Simplified offset.
15443 */
15444ol.geom.flat.simplify.douglasPeuckers = function(flatCoordinates, offset,
15445 ends, stride, squaredTolerance, simplifiedFlatCoordinates,
15446 simplifiedOffset, simplifiedEnds) {
15447 var i, ii;
15448 for (i = 0, ii = ends.length; i < ii; ++i) {
15449 var end = ends[i];
15450 simplifiedOffset = ol.geom.flat.simplify.douglasPeucker(
15451 flatCoordinates, offset, end, stride, squaredTolerance,
15452 simplifiedFlatCoordinates, simplifiedOffset);
15453 simplifiedEnds.push(simplifiedOffset);
15454 offset = end;
15455 }
15456 return simplifiedOffset;
15457};
15458
15459
15460/**
15461 * @param {Array.<number>} flatCoordinates Flat coordinates.
15462 * @param {number} offset Offset.
15463 * @param {Array.<Array.<number>>} endss Endss.
15464 * @param {number} stride Stride.
15465 * @param {number} squaredTolerance Squared tolerance.
15466 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15467 * coordinates.
15468 * @param {number} simplifiedOffset Simplified offset.
15469 * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
15470 * @return {number} Simplified offset.
15471 */
15472ol.geom.flat.simplify.douglasPeuckerss = function(
15473 flatCoordinates, offset, endss, stride, squaredTolerance,
15474 simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
15475 var i, ii;
15476 for (i = 0, ii = endss.length; i < ii; ++i) {
15477 var ends = endss[i];
15478 var simplifiedEnds = [];
15479 simplifiedOffset = ol.geom.flat.simplify.douglasPeuckers(
15480 flatCoordinates, offset, ends, stride, squaredTolerance,
15481 simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
15482 simplifiedEndss.push(simplifiedEnds);
15483 offset = ends[ends.length - 1];
15484 }
15485 return simplifiedOffset;
15486};
15487
15488
15489/**
15490 * @param {Array.<number>} flatCoordinates Flat coordinates.
15491 * @param {number} offset Offset.
15492 * @param {number} end End.
15493 * @param {number} stride Stride.
15494 * @param {number} squaredTolerance Squared tolerance.
15495 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15496 * coordinates.
15497 * @param {number} simplifiedOffset Simplified offset.
15498 * @return {number} Simplified offset.
15499 */
15500ol.geom.flat.simplify.radialDistance = function(flatCoordinates, offset, end,
15501 stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
15502 if (end <= offset + stride) {
15503 // zero or one point, no simplification possible, so copy and return
15504 for (; offset < end; offset += stride) {
15505 simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];
15506 simplifiedFlatCoordinates[simplifiedOffset++] =
15507 flatCoordinates[offset + 1];
15508 }
15509 return simplifiedOffset;
15510 }
15511 var x1 = flatCoordinates[offset];
15512 var y1 = flatCoordinates[offset + 1];
15513 // copy first point
15514 simplifiedFlatCoordinates[simplifiedOffset++] = x1;
15515 simplifiedFlatCoordinates[simplifiedOffset++] = y1;
15516 var x2 = x1;
15517 var y2 = y1;
15518 for (offset += stride; offset < end; offset += stride) {
15519 x2 = flatCoordinates[offset];
15520 y2 = flatCoordinates[offset + 1];
15521 if (ol.math.squaredDistance(x1, y1, x2, y2) > squaredTolerance) {
15522 // copy point at offset
15523 simplifiedFlatCoordinates[simplifiedOffset++] = x2;
15524 simplifiedFlatCoordinates[simplifiedOffset++] = y2;
15525 x1 = x2;
15526 y1 = y2;
15527 }
15528 }
15529 if (x2 != x1 || y2 != y1) {
15530 // copy last point
15531 simplifiedFlatCoordinates[simplifiedOffset++] = x2;
15532 simplifiedFlatCoordinates[simplifiedOffset++] = y2;
15533 }
15534 return simplifiedOffset;
15535};
15536
15537
15538/**
15539 * @param {number} value Value.
15540 * @param {number} tolerance Tolerance.
15541 * @return {number} Rounded value.
15542 */
15543ol.geom.flat.simplify.snap = function(value, tolerance) {
15544 return tolerance * Math.round(value / tolerance);
15545};
15546
15547
15548/**
15549 * Simplifies a line string using an algorithm designed by Tim Schaub.
15550 * Coordinates are snapped to the nearest value in a virtual grid and
15551 * consecutive duplicate coordinates are discarded. This effectively preserves
15552 * topology as the simplification of any subsection of a line string is
15553 * independent of the rest of the line string. This means that, for examples,
15554 * the common edge between two polygons will be simplified to the same line
15555 * string independently in both polygons. This implementation uses a single
15556 * pass over the coordinates and eliminates intermediate collinear points.
15557 * @param {Array.<number>} flatCoordinates Flat coordinates.
15558 * @param {number} offset Offset.
15559 * @param {number} end End.
15560 * @param {number} stride Stride.
15561 * @param {number} tolerance Tolerance.
15562 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15563 * coordinates.
15564 * @param {number} simplifiedOffset Simplified offset.
15565 * @return {number} Simplified offset.
15566 */
15567ol.geom.flat.simplify.quantize = function(flatCoordinates, offset, end, stride,
15568 tolerance, simplifiedFlatCoordinates, simplifiedOffset) {
15569 // do nothing if the line is empty
15570 if (offset == end) {
15571 return simplifiedOffset;
15572 }
15573 // snap the first coordinate (P1)
15574 var x1 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
15575 var y1 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
15576 offset += stride;
15577 // add the first coordinate to the output
15578 simplifiedFlatCoordinates[simplifiedOffset++] = x1;
15579 simplifiedFlatCoordinates[simplifiedOffset++] = y1;
15580 // find the next coordinate that does not snap to the same value as the first
15581 // coordinate (P2)
15582 var x2, y2;
15583 do {
15584 x2 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
15585 y2 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
15586 offset += stride;
15587 if (offset == end) {
15588 // all coordinates snap to the same value, the line collapses to a point
15589 // push the last snapped value anyway to ensure that the output contains
15590 // at least two points
15591 // FIXME should we really return at least two points anyway?
15592 simplifiedFlatCoordinates[simplifiedOffset++] = x2;
15593 simplifiedFlatCoordinates[simplifiedOffset++] = y2;
15594 return simplifiedOffset;
15595 }
15596 } while (x2 == x1 && y2 == y1);
15597 while (offset < end) {
15598 var x3, y3;
15599 // snap the next coordinate (P3)
15600 x3 = ol.geom.flat.simplify.snap(flatCoordinates[offset], tolerance);
15601 y3 = ol.geom.flat.simplify.snap(flatCoordinates[offset + 1], tolerance);
15602 offset += stride;
15603 // skip P3 if it is equal to P2
15604 if (x3 == x2 && y3 == y2) {
15605 continue;
15606 }
15607 // calculate the delta between P1 and P2
15608 var dx1 = x2 - x1;
15609 var dy1 = y2 - y1;
15610 // calculate the delta between P3 and P1
15611 var dx2 = x3 - x1;
15612 var dy2 = y3 - y1;
15613 // if P1, P2, and P3 are colinear and P3 is further from P1 than P2 is from
15614 // P1 in the same direction then P2 is on the straight line between P1 and
15615 // P3
15616 if ((dx1 * dy2 == dy1 * dx2) &&
15617 ((dx1 < 0 && dx2 < dx1) || dx1 == dx2 || (dx1 > 0 && dx2 > dx1)) &&
15618 ((dy1 < 0 && dy2 < dy1) || dy1 == dy2 || (dy1 > 0 && dy2 > dy1))) {
15619 // discard P2 and set P2 = P3
15620 x2 = x3;
15621 y2 = y3;
15622 continue;
15623 }
15624 // either P1, P2, and P3 are not colinear, or they are colinear but P3 is
15625 // between P3 and P1 or on the opposite half of the line to P2. add P2,
15626 // and continue with P1 = P2 and P2 = P3
15627 simplifiedFlatCoordinates[simplifiedOffset++] = x2;
15628 simplifiedFlatCoordinates[simplifiedOffset++] = y2;
15629 x1 = x2;
15630 y1 = y2;
15631 x2 = x3;
15632 y2 = y3;
15633 }
15634 // add the last point (P2)
15635 simplifiedFlatCoordinates[simplifiedOffset++] = x2;
15636 simplifiedFlatCoordinates[simplifiedOffset++] = y2;
15637 return simplifiedOffset;
15638};
15639
15640
15641/**
15642 * @param {Array.<number>} flatCoordinates Flat coordinates.
15643 * @param {number} offset Offset.
15644 * @param {Array.<number>} ends Ends.
15645 * @param {number} stride Stride.
15646 * @param {number} tolerance Tolerance.
15647 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15648 * coordinates.
15649 * @param {number} simplifiedOffset Simplified offset.
15650 * @param {Array.<number>} simplifiedEnds Simplified ends.
15651 * @return {number} Simplified offset.
15652 */
15653ol.geom.flat.simplify.quantizes = function(
15654 flatCoordinates, offset, ends, stride,
15655 tolerance,
15656 simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds) {
15657 var i, ii;
15658 for (i = 0, ii = ends.length; i < ii; ++i) {
15659 var end = ends[i];
15660 simplifiedOffset = ol.geom.flat.simplify.quantize(
15661 flatCoordinates, offset, end, stride,
15662 tolerance,
15663 simplifiedFlatCoordinates, simplifiedOffset);
15664 simplifiedEnds.push(simplifiedOffset);
15665 offset = end;
15666 }
15667 return simplifiedOffset;
15668};
15669
15670
15671/**
15672 * @param {Array.<number>} flatCoordinates Flat coordinates.
15673 * @param {number} offset Offset.
15674 * @param {Array.<Array.<number>>} endss Endss.
15675 * @param {number} stride Stride.
15676 * @param {number} tolerance Tolerance.
15677 * @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
15678 * coordinates.
15679 * @param {number} simplifiedOffset Simplified offset.
15680 * @param {Array.<Array.<number>>} simplifiedEndss Simplified endss.
15681 * @return {number} Simplified offset.
15682 */
15683ol.geom.flat.simplify.quantizess = function(
15684 flatCoordinates, offset, endss, stride,
15685 tolerance,
15686 simplifiedFlatCoordinates, simplifiedOffset, simplifiedEndss) {
15687 var i, ii;
15688 for (i = 0, ii = endss.length; i < ii; ++i) {
15689 var ends = endss[i];
15690 var simplifiedEnds = [];
15691 simplifiedOffset = ol.geom.flat.simplify.quantizes(
15692 flatCoordinates, offset, ends, stride,
15693 tolerance,
15694 simplifiedFlatCoordinates, simplifiedOffset, simplifiedEnds);
15695 simplifiedEndss.push(simplifiedEnds);
15696 offset = ends[ends.length - 1];
15697 }
15698 return simplifiedOffset;
15699};
15700
15701goog.provide('ol.geom.LinearRing');
15702
15703goog.require('ol');
15704goog.require('ol.extent');
15705goog.require('ol.geom.GeometryLayout');
15706goog.require('ol.geom.GeometryType');
15707goog.require('ol.geom.SimpleGeometry');
15708goog.require('ol.geom.flat.area');
15709goog.require('ol.geom.flat.closest');
15710goog.require('ol.geom.flat.deflate');
15711goog.require('ol.geom.flat.inflate');
15712goog.require('ol.geom.flat.simplify');
15713
15714
15715/**
15716 * @classdesc
15717 * Linear ring geometry. Only used as part of polygon; cannot be rendered
15718 * on its own.
15719 *
15720 * @constructor
15721 * @extends {ol.geom.SimpleGeometry}
15722 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
15723 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
15724 * @api
15725 */
15726ol.geom.LinearRing = function(coordinates, opt_layout) {
15727
15728 ol.geom.SimpleGeometry.call(this);
15729
15730 /**
15731 * @private
15732 * @type {number}
15733 */
15734 this.maxDelta_ = -1;
15735
15736 /**
15737 * @private
15738 * @type {number}
15739 */
15740 this.maxDeltaRevision_ = -1;
15741
15742 this.setCoordinates(coordinates, opt_layout);
15743
15744};
15745ol.inherits(ol.geom.LinearRing, ol.geom.SimpleGeometry);
15746
15747
15748/**
15749 * Make a complete copy of the geometry.
15750 * @return {!ol.geom.LinearRing} Clone.
15751 * @override
15752 * @api
15753 */
15754ol.geom.LinearRing.prototype.clone = function() {
15755 var linearRing = new ol.geom.LinearRing(null);
15756 linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
15757 return linearRing;
15758};
15759
15760
15761/**
15762 * @inheritDoc
15763 */
15764ol.geom.LinearRing.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
15765 if (minSquaredDistance <
15766 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
15767 return minSquaredDistance;
15768 }
15769 if (this.maxDeltaRevision_ != this.getRevision()) {
15770 this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
15771 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
15772 this.maxDeltaRevision_ = this.getRevision();
15773 }
15774 return ol.geom.flat.closest.getClosestPoint(
15775 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
15776 this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
15777};
15778
15779
15780/**
15781 * Return the area of the linear ring on projected plane.
15782 * @return {number} Area (on projected plane).
15783 * @api
15784 */
15785ol.geom.LinearRing.prototype.getArea = function() {
15786 return ol.geom.flat.area.linearRing(
15787 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
15788};
15789
15790
15791/**
15792 * Return the coordinates of the linear ring.
15793 * @return {Array.<ol.Coordinate>} Coordinates.
15794 * @override
15795 * @api
15796 */
15797ol.geom.LinearRing.prototype.getCoordinates = function() {
15798 return ol.geom.flat.inflate.coordinates(
15799 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
15800};
15801
15802
15803/**
15804 * @inheritDoc
15805 */
15806ol.geom.LinearRing.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
15807 var simplifiedFlatCoordinates = [];
15808 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
15809 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
15810 squaredTolerance, simplifiedFlatCoordinates, 0);
15811 var simplifiedLinearRing = new ol.geom.LinearRing(null);
15812 simplifiedLinearRing.setFlatCoordinates(
15813 ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
15814 return simplifiedLinearRing;
15815};
15816
15817
15818/**
15819 * @inheritDoc
15820 * @api
15821 */
15822ol.geom.LinearRing.prototype.getType = function() {
15823 return ol.geom.GeometryType.LINEAR_RING;
15824};
15825
15826
15827/**
15828 * @inheritDoc
15829 */
15830ol.geom.LinearRing.prototype.intersectsExtent = function(extent) {};
15831
15832
15833/**
15834 * Set the coordinates of the linear ring.
15835 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
15836 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
15837 * @override
15838 * @api
15839 */
15840ol.geom.LinearRing.prototype.setCoordinates = function(coordinates, opt_layout) {
15841 if (!coordinates) {
15842 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
15843 } else {
15844 this.setLayout(opt_layout, coordinates, 1);
15845 if (!this.flatCoordinates) {
15846 this.flatCoordinates = [];
15847 }
15848 this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
15849 this.flatCoordinates, 0, coordinates, this.stride);
15850 this.changed();
15851 }
15852};
15853
15854
15855/**
15856 * @param {ol.geom.GeometryLayout} layout Layout.
15857 * @param {Array.<number>} flatCoordinates Flat coordinates.
15858 */
15859ol.geom.LinearRing.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
15860 this.setFlatCoordinatesInternal(layout, flatCoordinates);
15861 this.changed();
15862};
15863
15864goog.provide('ol.geom.Point');
15865
15866goog.require('ol');
15867goog.require('ol.extent');
15868goog.require('ol.geom.GeometryLayout');
15869goog.require('ol.geom.GeometryType');
15870goog.require('ol.geom.SimpleGeometry');
15871goog.require('ol.geom.flat.deflate');
15872goog.require('ol.math');
15873
15874
15875/**
15876 * @classdesc
15877 * Point geometry.
15878 *
15879 * @constructor
15880 * @extends {ol.geom.SimpleGeometry}
15881 * @param {ol.Coordinate} coordinates Coordinates.
15882 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
15883 * @api
15884 */
15885ol.geom.Point = function(coordinates, opt_layout) {
15886 ol.geom.SimpleGeometry.call(this);
15887 this.setCoordinates(coordinates, opt_layout);
15888};
15889ol.inherits(ol.geom.Point, ol.geom.SimpleGeometry);
15890
15891
15892/**
15893 * Make a complete copy of the geometry.
15894 * @return {!ol.geom.Point} Clone.
15895 * @override
15896 * @api
15897 */
15898ol.geom.Point.prototype.clone = function() {
15899 var point = new ol.geom.Point(null);
15900 point.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
15901 return point;
15902};
15903
15904
15905/**
15906 * @inheritDoc
15907 */
15908ol.geom.Point.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
15909 var flatCoordinates = this.flatCoordinates;
15910 var squaredDistance = ol.math.squaredDistance(
15911 x, y, flatCoordinates[0], flatCoordinates[1]);
15912 if (squaredDistance < minSquaredDistance) {
15913 var stride = this.stride;
15914 var i;
15915 for (i = 0; i < stride; ++i) {
15916 closestPoint[i] = flatCoordinates[i];
15917 }
15918 closestPoint.length = stride;
15919 return squaredDistance;
15920 } else {
15921 return minSquaredDistance;
15922 }
15923};
15924
15925
15926/**
15927 * Return the coordinate of the point.
15928 * @return {ol.Coordinate} Coordinates.
15929 * @override
15930 * @api
15931 */
15932ol.geom.Point.prototype.getCoordinates = function() {
15933 return !this.flatCoordinates ? [] : this.flatCoordinates.slice();
15934};
15935
15936
15937/**
15938 * @inheritDoc
15939 */
15940ol.geom.Point.prototype.computeExtent = function(extent) {
15941 return ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates, extent);
15942};
15943
15944
15945/**
15946 * @inheritDoc
15947 * @api
15948 */
15949ol.geom.Point.prototype.getType = function() {
15950 return ol.geom.GeometryType.POINT;
15951};
15952
15953
15954/**
15955 * @inheritDoc
15956 * @api
15957 */
15958ol.geom.Point.prototype.intersectsExtent = function(extent) {
15959 return ol.extent.containsXY(extent,
15960 this.flatCoordinates[0], this.flatCoordinates[1]);
15961};
15962
15963
15964/**
15965 * @inheritDoc
15966 * @api
15967 */
15968ol.geom.Point.prototype.setCoordinates = function(coordinates, opt_layout) {
15969 if (!coordinates) {
15970 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
15971 } else {
15972 this.setLayout(opt_layout, coordinates, 0);
15973 if (!this.flatCoordinates) {
15974 this.flatCoordinates = [];
15975 }
15976 this.flatCoordinates.length = ol.geom.flat.deflate.coordinate(
15977 this.flatCoordinates, 0, coordinates, this.stride);
15978 this.changed();
15979 }
15980};
15981
15982
15983/**
15984 * @param {ol.geom.GeometryLayout} layout Layout.
15985 * @param {Array.<number>} flatCoordinates Flat coordinates.
15986 */
15987ol.geom.Point.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
15988 this.setFlatCoordinatesInternal(layout, flatCoordinates);
15989 this.changed();
15990};
15991
15992goog.provide('ol.geom.flat.contains');
15993
15994goog.require('ol.extent');
15995
15996
15997/**
15998 * @param {Array.<number>} flatCoordinates Flat coordinates.
15999 * @param {number} offset Offset.
16000 * @param {number} end End.
16001 * @param {number} stride Stride.
16002 * @param {ol.Extent} extent Extent.
16003 * @return {boolean} Contains extent.
16004 */
16005ol.geom.flat.contains.linearRingContainsExtent = function(flatCoordinates, offset, end, stride, extent) {
16006 var outside = ol.extent.forEachCorner(extent,
16007 /**
16008 * @param {ol.Coordinate} coordinate Coordinate.
16009 * @return {boolean} Contains (x, y).
16010 */
16011 function(coordinate) {
16012 return !ol.geom.flat.contains.linearRingContainsXY(flatCoordinates,
16013 offset, end, stride, coordinate[0], coordinate[1]);
16014 });
16015 return !outside;
16016};
16017
16018
16019/**
16020 * @param {Array.<number>} flatCoordinates Flat coordinates.
16021 * @param {number} offset Offset.
16022 * @param {number} end End.
16023 * @param {number} stride Stride.
16024 * @param {number} x X.
16025 * @param {number} y Y.
16026 * @return {boolean} Contains (x, y).
16027 */
16028ol.geom.flat.contains.linearRingContainsXY = function(flatCoordinates, offset, end, stride, x, y) {
16029 // http://geomalgorithms.com/a03-_inclusion.html
16030 // Copyright 2000 softSurfer, 2012 Dan Sunday
16031 // This code may be freely used and modified for any purpose
16032 // providing that this copyright notice is included with it.
16033 // SoftSurfer makes no warranty for this code, and cannot be held
16034 // liable for any real or imagined damage resulting from its use.
16035 // Users of this code must verify correctness for their application.
16036 var wn = 0;
16037 var x1 = flatCoordinates[end - stride];
16038 var y1 = flatCoordinates[end - stride + 1];
16039 for (; offset < end; offset += stride) {
16040 var x2 = flatCoordinates[offset];
16041 var y2 = flatCoordinates[offset + 1];
16042 if (y1 <= y) {
16043 if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) {
16044 wn++;
16045 }
16046 } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) {
16047 wn--;
16048 }
16049 x1 = x2;
16050 y1 = y2;
16051 }
16052 return wn !== 0;
16053};
16054
16055
16056/**
16057 * @param {Array.<number>} flatCoordinates Flat coordinates.
16058 * @param {number} offset Offset.
16059 * @param {Array.<number>} ends Ends.
16060 * @param {number} stride Stride.
16061 * @param {number} x X.
16062 * @param {number} y Y.
16063 * @return {boolean} Contains (x, y).
16064 */
16065ol.geom.flat.contains.linearRingsContainsXY = function(flatCoordinates, offset, ends, stride, x, y) {
16066 if (ends.length === 0) {
16067 return false;
16068 }
16069 if (!ol.geom.flat.contains.linearRingContainsXY(
16070 flatCoordinates, offset, ends[0], stride, x, y)) {
16071 return false;
16072 }
16073 var i, ii;
16074 for (i = 1, ii = ends.length; i < ii; ++i) {
16075 if (ol.geom.flat.contains.linearRingContainsXY(
16076 flatCoordinates, ends[i - 1], ends[i], stride, x, y)) {
16077 return false;
16078 }
16079 }
16080 return true;
16081};
16082
16083
16084/**
16085 * @param {Array.<number>} flatCoordinates Flat coordinates.
16086 * @param {number} offset Offset.
16087 * @param {Array.<Array.<number>>} endss Endss.
16088 * @param {number} stride Stride.
16089 * @param {number} x X.
16090 * @param {number} y Y.
16091 * @return {boolean} Contains (x, y).
16092 */
16093ol.geom.flat.contains.linearRingssContainsXY = function(flatCoordinates, offset, endss, stride, x, y) {
16094 if (endss.length === 0) {
16095 return false;
16096 }
16097 var i, ii;
16098 for (i = 0, ii = endss.length; i < ii; ++i) {
16099 var ends = endss[i];
16100 if (ol.geom.flat.contains.linearRingsContainsXY(
16101 flatCoordinates, offset, ends, stride, x, y)) {
16102 return true;
16103 }
16104 offset = ends[ends.length - 1];
16105 }
16106 return false;
16107};
16108
16109goog.provide('ol.geom.flat.interiorpoint');
16110
16111goog.require('ol.array');
16112goog.require('ol.geom.flat.contains');
16113
16114
16115/**
16116 * Calculates a point that is likely to lie in the interior of the linear rings.
16117 * Inspired by JTS's com.vividsolutions.jts.geom.Geometry#getInteriorPoint.
16118 * @param {Array.<number>} flatCoordinates Flat coordinates.
16119 * @param {number} offset Offset.
16120 * @param {Array.<number>} ends Ends.
16121 * @param {number} stride Stride.
16122 * @param {Array.<number>} flatCenters Flat centers.
16123 * @param {number} flatCentersOffset Flat center offset.
16124 * @param {Array.<number>=} opt_dest Destination.
16125 * @return {Array.<number>} Destination.
16126 */
16127ol.geom.flat.interiorpoint.linearRings = function(flatCoordinates, offset,
16128 ends, stride, flatCenters, flatCentersOffset, opt_dest) {
16129 var i, ii, x, x1, x2, y1, y2;
16130 var y = flatCenters[flatCentersOffset + 1];
16131 /** @type {Array.<number>} */
16132 var intersections = [];
16133 // Calculate intersections with the horizontal line
16134 var end = ends[0];
16135 x1 = flatCoordinates[end - stride];
16136 y1 = flatCoordinates[end - stride + 1];
16137 for (i = offset; i < end; i += stride) {
16138 x2 = flatCoordinates[i];
16139 y2 = flatCoordinates[i + 1];
16140 if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) {
16141 x = (y - y1) / (y2 - y1) * (x2 - x1) + x1;
16142 intersections.push(x);
16143 }
16144 x1 = x2;
16145 y1 = y2;
16146 }
16147 // Find the longest segment of the horizontal line that has its center point
16148 // inside the linear ring.
16149 var pointX = NaN;
16150 var maxSegmentLength = -Infinity;
16151 intersections.sort(ol.array.numberSafeCompareFunction);
16152 x1 = intersections[0];
16153 for (i = 1, ii = intersections.length; i < ii; ++i) {
16154 x2 = intersections[i];
16155 var segmentLength = Math.abs(x2 - x1);
16156 if (segmentLength > maxSegmentLength) {
16157 x = (x1 + x2) / 2;
16158 if (ol.geom.flat.contains.linearRingsContainsXY(
16159 flatCoordinates, offset, ends, stride, x, y)) {
16160 pointX = x;
16161 maxSegmentLength = segmentLength;
16162 }
16163 }
16164 x1 = x2;
16165 }
16166 if (isNaN(pointX)) {
16167 // There is no horizontal line that has its center point inside the linear
16168 // ring. Use the center of the the linear ring's extent.
16169 pointX = flatCenters[flatCentersOffset];
16170 }
16171 if (opt_dest) {
16172 opt_dest.push(pointX, y);
16173 return opt_dest;
16174 } else {
16175 return [pointX, y];
16176 }
16177};
16178
16179
16180/**
16181 * @param {Array.<number>} flatCoordinates Flat coordinates.
16182 * @param {number} offset Offset.
16183 * @param {Array.<Array.<number>>} endss Endss.
16184 * @param {number} stride Stride.
16185 * @param {Array.<number>} flatCenters Flat centers.
16186 * @return {Array.<number>} Interior points.
16187 */
16188ol.geom.flat.interiorpoint.linearRingss = function(flatCoordinates, offset, endss, stride, flatCenters) {
16189 var interiorPoints = [];
16190 var i, ii;
16191 for (i = 0, ii = endss.length; i < ii; ++i) {
16192 var ends = endss[i];
16193 interiorPoints = ol.geom.flat.interiorpoint.linearRings(flatCoordinates,
16194 offset, ends, stride, flatCenters, 2 * i, interiorPoints);
16195 offset = ends[ends.length - 1];
16196 }
16197 return interiorPoints;
16198};
16199
16200goog.provide('ol.geom.flat.segments');
16201
16202
16203/**
16204 * This function calls `callback` for each segment of the flat coordinates
16205 * array. If the callback returns a truthy value the function returns that
16206 * value immediately. Otherwise the function returns `false`.
16207 * @param {Array.<number>} flatCoordinates Flat coordinates.
16208 * @param {number} offset Offset.
16209 * @param {number} end End.
16210 * @param {number} stride Stride.
16211 * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
16212 * called for each segment.
16213 * @param {S=} opt_this The object to be used as the value of 'this'
16214 * within callback.
16215 * @return {T|boolean} Value.
16216 * @template T,S
16217 */
16218ol.geom.flat.segments.forEach = function(flatCoordinates, offset, end, stride, callback, opt_this) {
16219 var point1 = [flatCoordinates[offset], flatCoordinates[offset + 1]];
16220 var point2 = [];
16221 var ret;
16222 for (; (offset + stride) < end; offset += stride) {
16223 point2[0] = flatCoordinates[offset + stride];
16224 point2[1] = flatCoordinates[offset + stride + 1];
16225 ret = callback.call(opt_this, point1, point2);
16226 if (ret) {
16227 return ret;
16228 }
16229 point1[0] = point2[0];
16230 point1[1] = point2[1];
16231 }
16232 return false;
16233};
16234
16235goog.provide('ol.geom.flat.intersectsextent');
16236
16237goog.require('ol.extent');
16238goog.require('ol.geom.flat.contains');
16239goog.require('ol.geom.flat.segments');
16240
16241
16242/**
16243 * @param {Array.<number>} flatCoordinates Flat coordinates.
16244 * @param {number} offset Offset.
16245 * @param {number} end End.
16246 * @param {number} stride Stride.
16247 * @param {ol.Extent} extent Extent.
16248 * @return {boolean} True if the geometry and the extent intersect.
16249 */
16250ol.geom.flat.intersectsextent.lineString = function(flatCoordinates, offset, end, stride, extent) {
16251 var coordinatesExtent = ol.extent.extendFlatCoordinates(
16252 ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
16253 if (!ol.extent.intersects(extent, coordinatesExtent)) {
16254 return false;
16255 }
16256 if (ol.extent.containsExtent(extent, coordinatesExtent)) {
16257 return true;
16258 }
16259 if (coordinatesExtent[0] >= extent[0] &&
16260 coordinatesExtent[2] <= extent[2]) {
16261 return true;
16262 }
16263 if (coordinatesExtent[1] >= extent[1] &&
16264 coordinatesExtent[3] <= extent[3]) {
16265 return true;
16266 }
16267 return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
16268 /**
16269 * @param {ol.Coordinate} point1 Start point.
16270 * @param {ol.Coordinate} point2 End point.
16271 * @return {boolean} `true` if the segment and the extent intersect,
16272 * `false` otherwise.
16273 */
16274 function(point1, point2) {
16275 return ol.extent.intersectsSegment(extent, point1, point2);
16276 });
16277};
16278
16279
16280/**
16281 * @param {Array.<number>} flatCoordinates Flat coordinates.
16282 * @param {number} offset Offset.
16283 * @param {Array.<number>} ends Ends.
16284 * @param {number} stride Stride.
16285 * @param {ol.Extent} extent Extent.
16286 * @return {boolean} True if the geometry and the extent intersect.
16287 */
16288ol.geom.flat.intersectsextent.lineStrings = function(flatCoordinates, offset, ends, stride, extent) {
16289 var i, ii;
16290 for (i = 0, ii = ends.length; i < ii; ++i) {
16291 if (ol.geom.flat.intersectsextent.lineString(
16292 flatCoordinates, offset, ends[i], stride, extent)) {
16293 return true;
16294 }
16295 offset = ends[i];
16296 }
16297 return false;
16298};
16299
16300
16301/**
16302 * @param {Array.<number>} flatCoordinates Flat coordinates.
16303 * @param {number} offset Offset.
16304 * @param {number} end End.
16305 * @param {number} stride Stride.
16306 * @param {ol.Extent} extent Extent.
16307 * @return {boolean} True if the geometry and the extent intersect.
16308 */
16309ol.geom.flat.intersectsextent.linearRing = function(flatCoordinates, offset, end, stride, extent) {
16310 if (ol.geom.flat.intersectsextent.lineString(
16311 flatCoordinates, offset, end, stride, extent)) {
16312 return true;
16313 }
16314 if (ol.geom.flat.contains.linearRingContainsXY(
16315 flatCoordinates, offset, end, stride, extent[0], extent[1])) {
16316 return true;
16317 }
16318 if (ol.geom.flat.contains.linearRingContainsXY(
16319 flatCoordinates, offset, end, stride, extent[0], extent[3])) {
16320 return true;
16321 }
16322 if (ol.geom.flat.contains.linearRingContainsXY(
16323 flatCoordinates, offset, end, stride, extent[2], extent[1])) {
16324 return true;
16325 }
16326 if (ol.geom.flat.contains.linearRingContainsXY(
16327 flatCoordinates, offset, end, stride, extent[2], extent[3])) {
16328 return true;
16329 }
16330 return false;
16331};
16332
16333
16334/**
16335 * @param {Array.<number>} flatCoordinates Flat coordinates.
16336 * @param {number} offset Offset.
16337 * @param {Array.<number>} ends Ends.
16338 * @param {number} stride Stride.
16339 * @param {ol.Extent} extent Extent.
16340 * @return {boolean} True if the geometry and the extent intersect.
16341 */
16342ol.geom.flat.intersectsextent.linearRings = function(flatCoordinates, offset, ends, stride, extent) {
16343 if (!ol.geom.flat.intersectsextent.linearRing(
16344 flatCoordinates, offset, ends[0], stride, extent)) {
16345 return false;
16346 }
16347 if (ends.length === 1) {
16348 return true;
16349 }
16350 var i, ii;
16351 for (i = 1, ii = ends.length; i < ii; ++i) {
16352 if (ol.geom.flat.contains.linearRingContainsExtent(
16353 flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
16354 return false;
16355 }
16356 }
16357 return true;
16358};
16359
16360
16361/**
16362 * @param {Array.<number>} flatCoordinates Flat coordinates.
16363 * @param {number} offset Offset.
16364 * @param {Array.<Array.<number>>} endss Endss.
16365 * @param {number} stride Stride.
16366 * @param {ol.Extent} extent Extent.
16367 * @return {boolean} True if the geometry and the extent intersect.
16368 */
16369ol.geom.flat.intersectsextent.linearRingss = function(flatCoordinates, offset, endss, stride, extent) {
16370 var i, ii;
16371 for (i = 0, ii = endss.length; i < ii; ++i) {
16372 var ends = endss[i];
16373 if (ol.geom.flat.intersectsextent.linearRings(
16374 flatCoordinates, offset, ends, stride, extent)) {
16375 return true;
16376 }
16377 offset = ends[ends.length - 1];
16378 }
16379 return false;
16380};
16381
16382goog.provide('ol.geom.flat.reverse');
16383
16384
16385/**
16386 * @param {Array.<number>} flatCoordinates Flat coordinates.
16387 * @param {number} offset Offset.
16388 * @param {number} end End.
16389 * @param {number} stride Stride.
16390 */
16391ol.geom.flat.reverse.coordinates = function(flatCoordinates, offset, end, stride) {
16392 while (offset < end - stride) {
16393 var i;
16394 for (i = 0; i < stride; ++i) {
16395 var tmp = flatCoordinates[offset + i];
16396 flatCoordinates[offset + i] = flatCoordinates[end - stride + i];
16397 flatCoordinates[end - stride + i] = tmp;
16398 }
16399 offset += stride;
16400 end -= stride;
16401 }
16402};
16403
16404goog.provide('ol.geom.flat.orient');
16405
16406goog.require('ol.geom.flat.reverse');
16407
16408
16409/**
16410 * @param {Array.<number>} flatCoordinates Flat coordinates.
16411 * @param {number} offset Offset.
16412 * @param {number} end End.
16413 * @param {number} stride Stride.
16414 * @return {boolean} Is clockwise.
16415 */
16416ol.geom.flat.orient.linearRingIsClockwise = function(flatCoordinates, offset, end, stride) {
16417 // http://tinyurl.com/clockwise-method
16418 // https://github.com/OSGeo/gdal/blob/trunk/gdal/ogr/ogrlinearring.cpp
16419 var edge = 0;
16420 var x1 = flatCoordinates[end - stride];
16421 var y1 = flatCoordinates[end - stride + 1];
16422 for (; offset < end; offset += stride) {
16423 var x2 = flatCoordinates[offset];
16424 var y2 = flatCoordinates[offset + 1];
16425 edge += (x2 - x1) * (y2 + y1);
16426 x1 = x2;
16427 y1 = y2;
16428 }
16429 return edge > 0;
16430};
16431
16432
16433/**
16434 * Determines if linear rings are oriented. By default, left-hand orientation
16435 * is tested (first ring must be clockwise, remaining rings counter-clockwise).
16436 * To test for right-hand orientation, use the `opt_right` argument.
16437 *
16438 * @param {Array.<number>} flatCoordinates Flat coordinates.
16439 * @param {number} offset Offset.
16440 * @param {Array.<number>} ends Array of end indexes.
16441 * @param {number} stride Stride.
16442 * @param {boolean=} opt_right Test for right-hand orientation
16443 * (counter-clockwise exterior ring and clockwise interior rings).
16444 * @return {boolean} Rings are correctly oriented.
16445 */
16446ol.geom.flat.orient.linearRingsAreOriented = function(flatCoordinates, offset, ends, stride, opt_right) {
16447 var right = opt_right !== undefined ? opt_right : false;
16448 var i, ii;
16449 for (i = 0, ii = ends.length; i < ii; ++i) {
16450 var end = ends[i];
16451 var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
16452 flatCoordinates, offset, end, stride);
16453 if (i === 0) {
16454 if ((right && isClockwise) || (!right && !isClockwise)) {
16455 return false;
16456 }
16457 } else {
16458 if ((right && !isClockwise) || (!right && isClockwise)) {
16459 return false;
16460 }
16461 }
16462 offset = end;
16463 }
16464 return true;
16465};
16466
16467
16468/**
16469 * Determines if linear rings are oriented. By default, left-hand orientation
16470 * is tested (first ring must be clockwise, remaining rings counter-clockwise).
16471 * To test for right-hand orientation, use the `opt_right` argument.
16472 *
16473 * @param {Array.<number>} flatCoordinates Flat coordinates.
16474 * @param {number} offset Offset.
16475 * @param {Array.<Array.<number>>} endss Array of array of end indexes.
16476 * @param {number} stride Stride.
16477 * @param {boolean=} opt_right Test for right-hand orientation
16478 * (counter-clockwise exterior ring and clockwise interior rings).
16479 * @return {boolean} Rings are correctly oriented.
16480 */
16481ol.geom.flat.orient.linearRingssAreOriented = function(flatCoordinates, offset, endss, stride, opt_right) {
16482 var i, ii;
16483 for (i = 0, ii = endss.length; i < ii; ++i) {
16484 if (!ol.geom.flat.orient.linearRingsAreOriented(
16485 flatCoordinates, offset, endss[i], stride, opt_right)) {
16486 return false;
16487 }
16488 }
16489 return true;
16490};
16491
16492
16493/**
16494 * Orient coordinates in a flat array of linear rings. By default, rings
16495 * are oriented following the left-hand rule (clockwise for exterior and
16496 * counter-clockwise for interior rings). To orient according to the
16497 * right-hand rule, use the `opt_right` argument.
16498 *
16499 * @param {Array.<number>} flatCoordinates Flat coordinates.
16500 * @param {number} offset Offset.
16501 * @param {Array.<number>} ends Ends.
16502 * @param {number} stride Stride.
16503 * @param {boolean=} opt_right Follow the right-hand rule for orientation.
16504 * @return {number} End.
16505 */
16506ol.geom.flat.orient.orientLinearRings = function(flatCoordinates, offset, ends, stride, opt_right) {
16507 var right = opt_right !== undefined ? opt_right : false;
16508 var i, ii;
16509 for (i = 0, ii = ends.length; i < ii; ++i) {
16510 var end = ends[i];
16511 var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(
16512 flatCoordinates, offset, end, stride);
16513 var reverse = i === 0 ?
16514 (right && isClockwise) || (!right && !isClockwise) :
16515 (right && !isClockwise) || (!right && isClockwise);
16516 if (reverse) {
16517 ol.geom.flat.reverse.coordinates(flatCoordinates, offset, end, stride);
16518 }
16519 offset = end;
16520 }
16521 return offset;
16522};
16523
16524
16525/**
16526 * Orient coordinates in a flat array of linear rings. By default, rings
16527 * are oriented following the left-hand rule (clockwise for exterior and
16528 * counter-clockwise for interior rings). To orient according to the
16529 * right-hand rule, use the `opt_right` argument.
16530 *
16531 * @param {Array.<number>} flatCoordinates Flat coordinates.
16532 * @param {number} offset Offset.
16533 * @param {Array.<Array.<number>>} endss Array of array of end indexes.
16534 * @param {number} stride Stride.
16535 * @param {boolean=} opt_right Follow the right-hand rule for orientation.
16536 * @return {number} End.
16537 */
16538ol.geom.flat.orient.orientLinearRingss = function(flatCoordinates, offset, endss, stride, opt_right) {
16539 var i, ii;
16540 for (i = 0, ii = endss.length; i < ii; ++i) {
16541 offset = ol.geom.flat.orient.orientLinearRings(
16542 flatCoordinates, offset, endss[i], stride, opt_right);
16543 }
16544 return offset;
16545};
16546
16547goog.provide('ol.geom.Polygon');
16548
16549goog.require('ol');
16550goog.require('ol.array');
16551goog.require('ol.extent');
16552goog.require('ol.geom.GeometryLayout');
16553goog.require('ol.geom.GeometryType');
16554goog.require('ol.geom.LinearRing');
16555goog.require('ol.geom.Point');
16556goog.require('ol.geom.SimpleGeometry');
16557goog.require('ol.geom.flat.area');
16558goog.require('ol.geom.flat.closest');
16559goog.require('ol.geom.flat.contains');
16560goog.require('ol.geom.flat.deflate');
16561goog.require('ol.geom.flat.inflate');
16562goog.require('ol.geom.flat.interiorpoint');
16563goog.require('ol.geom.flat.intersectsextent');
16564goog.require('ol.geom.flat.orient');
16565goog.require('ol.geom.flat.simplify');
16566goog.require('ol.math');
16567
16568
16569/**
16570 * @classdesc
16571 * Polygon geometry.
16572 *
16573 * @constructor
16574 * @extends {ol.geom.SimpleGeometry}
16575 * @param {Array.<Array.<ol.Coordinate>>} coordinates Array of linear
16576 * rings that define the polygon. The first linear ring of the array
16577 * defines the outer-boundary or surface of the polygon. Each subsequent
16578 * linear ring defines a hole in the surface of the polygon. A linear ring
16579 * is an array of vertices' coordinates where the first coordinate and the
16580 * last are equivalent.
16581 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
16582 * @api
16583 */
16584ol.geom.Polygon = function(coordinates, opt_layout) {
16585
16586 ol.geom.SimpleGeometry.call(this);
16587
16588 /**
16589 * @type {Array.<number>}
16590 * @private
16591 */
16592 this.ends_ = [];
16593
16594 /**
16595 * @private
16596 * @type {number}
16597 */
16598 this.flatInteriorPointRevision_ = -1;
16599
16600 /**
16601 * @private
16602 * @type {ol.Coordinate}
16603 */
16604 this.flatInteriorPoint_ = null;
16605
16606 /**
16607 * @private
16608 * @type {number}
16609 */
16610 this.maxDelta_ = -1;
16611
16612 /**
16613 * @private
16614 * @type {number}
16615 */
16616 this.maxDeltaRevision_ = -1;
16617
16618 /**
16619 * @private
16620 * @type {number}
16621 */
16622 this.orientedRevision_ = -1;
16623
16624 /**
16625 * @private
16626 * @type {Array.<number>}
16627 */
16628 this.orientedFlatCoordinates_ = null;
16629
16630 this.setCoordinates(coordinates, opt_layout);
16631
16632};
16633ol.inherits(ol.geom.Polygon, ol.geom.SimpleGeometry);
16634
16635
16636/**
16637 * Append the passed linear ring to this polygon.
16638 * @param {ol.geom.LinearRing} linearRing Linear ring.
16639 * @api
16640 */
16641ol.geom.Polygon.prototype.appendLinearRing = function(linearRing) {
16642 if (!this.flatCoordinates) {
16643 this.flatCoordinates = linearRing.getFlatCoordinates().slice();
16644 } else {
16645 ol.array.extend(this.flatCoordinates, linearRing.getFlatCoordinates());
16646 }
16647 this.ends_.push(this.flatCoordinates.length);
16648 this.changed();
16649};
16650
16651
16652/**
16653 * Make a complete copy of the geometry.
16654 * @return {!ol.geom.Polygon} Clone.
16655 * @override
16656 * @api
16657 */
16658ol.geom.Polygon.prototype.clone = function() {
16659 var polygon = new ol.geom.Polygon(null);
16660 polygon.setFlatCoordinates(
16661 this.layout, this.flatCoordinates.slice(), this.ends_.slice());
16662 return polygon;
16663};
16664
16665
16666/**
16667 * @inheritDoc
16668 */
16669ol.geom.Polygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
16670 if (minSquaredDistance <
16671 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
16672 return minSquaredDistance;
16673 }
16674 if (this.maxDeltaRevision_ != this.getRevision()) {
16675 this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
16676 this.flatCoordinates, 0, this.ends_, this.stride, 0));
16677 this.maxDeltaRevision_ = this.getRevision();
16678 }
16679 return ol.geom.flat.closest.getsClosestPoint(
16680 this.flatCoordinates, 0, this.ends_, this.stride,
16681 this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
16682};
16683
16684
16685/**
16686 * @inheritDoc
16687 */
16688ol.geom.Polygon.prototype.containsXY = function(x, y) {
16689 return ol.geom.flat.contains.linearRingsContainsXY(
16690 this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, x, y);
16691};
16692
16693
16694/**
16695 * Return the area of the polygon on projected plane.
16696 * @return {number} Area (on projected plane).
16697 * @api
16698 */
16699ol.geom.Polygon.prototype.getArea = function() {
16700 return ol.geom.flat.area.linearRings(
16701 this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride);
16702};
16703
16704
16705/**
16706 * Get the coordinate array for this geometry. This array has the structure
16707 * of a GeoJSON coordinate array for polygons.
16708 *
16709 * @param {boolean=} opt_right Orient coordinates according to the right-hand
16710 * rule (counter-clockwise for exterior and clockwise for interior rings).
16711 * If `false`, coordinates will be oriented according to the left-hand rule
16712 * (clockwise for exterior and counter-clockwise for interior rings).
16713 * By default, coordinate orientation will depend on how the geometry was
16714 * constructed.
16715 * @return {Array.<Array.<ol.Coordinate>>} Coordinates.
16716 * @override
16717 * @api
16718 */
16719ol.geom.Polygon.prototype.getCoordinates = function(opt_right) {
16720 var flatCoordinates;
16721 if (opt_right !== undefined) {
16722 flatCoordinates = this.getOrientedFlatCoordinates().slice();
16723 ol.geom.flat.orient.orientLinearRings(
16724 flatCoordinates, 0, this.ends_, this.stride, opt_right);
16725 } else {
16726 flatCoordinates = this.flatCoordinates;
16727 }
16728
16729 return ol.geom.flat.inflate.coordinatess(
16730 flatCoordinates, 0, this.ends_, this.stride);
16731};
16732
16733
16734/**
16735 * @return {Array.<number>} Ends.
16736 */
16737ol.geom.Polygon.prototype.getEnds = function() {
16738 return this.ends_;
16739};
16740
16741
16742/**
16743 * @return {Array.<number>} Interior point.
16744 */
16745ol.geom.Polygon.prototype.getFlatInteriorPoint = function() {
16746 if (this.flatInteriorPointRevision_ != this.getRevision()) {
16747 var flatCenter = ol.extent.getCenter(this.getExtent());
16748 this.flatInteriorPoint_ = ol.geom.flat.interiorpoint.linearRings(
16749 this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride,
16750 flatCenter, 0);
16751 this.flatInteriorPointRevision_ = this.getRevision();
16752 }
16753 return this.flatInteriorPoint_;
16754};
16755
16756
16757/**
16758 * Return an interior point of the polygon.
16759 * @return {ol.geom.Point} Interior point.
16760 * @api
16761 */
16762ol.geom.Polygon.prototype.getInteriorPoint = function() {
16763 return new ol.geom.Point(this.getFlatInteriorPoint());
16764};
16765
16766
16767/**
16768 * Return the number of rings of the polygon, this includes the exterior
16769 * ring and any interior rings.
16770 *
16771 * @return {number} Number of rings.
16772 * @api
16773 */
16774ol.geom.Polygon.prototype.getLinearRingCount = function() {
16775 return this.ends_.length;
16776};
16777
16778
16779/**
16780 * Return the Nth linear ring of the polygon geometry. Return `null` if the
16781 * given index is out of range.
16782 * The exterior linear ring is available at index `0` and the interior rings
16783 * at index `1` and beyond.
16784 *
16785 * @param {number} index Index.
16786 * @return {ol.geom.LinearRing} Linear ring.
16787 * @api
16788 */
16789ol.geom.Polygon.prototype.getLinearRing = function(index) {
16790 if (index < 0 || this.ends_.length <= index) {
16791 return null;
16792 }
16793 var linearRing = new ol.geom.LinearRing(null);
16794 linearRing.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
16795 index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
16796 return linearRing;
16797};
16798
16799
16800/**
16801 * Return the linear rings of the polygon.
16802 * @return {Array.<ol.geom.LinearRing>} Linear rings.
16803 * @api
16804 */
16805ol.geom.Polygon.prototype.getLinearRings = function() {
16806 var layout = this.layout;
16807 var flatCoordinates = this.flatCoordinates;
16808 var ends = this.ends_;
16809 var linearRings = [];
16810 var offset = 0;
16811 var i, ii;
16812 for (i = 0, ii = ends.length; i < ii; ++i) {
16813 var end = ends[i];
16814 var linearRing = new ol.geom.LinearRing(null);
16815 linearRing.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
16816 linearRings.push(linearRing);
16817 offset = end;
16818 }
16819 return linearRings;
16820};
16821
16822
16823/**
16824 * @return {Array.<number>} Oriented flat coordinates.
16825 */
16826ol.geom.Polygon.prototype.getOrientedFlatCoordinates = function() {
16827 if (this.orientedRevision_ != this.getRevision()) {
16828 var flatCoordinates = this.flatCoordinates;
16829 if (ol.geom.flat.orient.linearRingsAreOriented(
16830 flatCoordinates, 0, this.ends_, this.stride)) {
16831 this.orientedFlatCoordinates_ = flatCoordinates;
16832 } else {
16833 this.orientedFlatCoordinates_ = flatCoordinates.slice();
16834 this.orientedFlatCoordinates_.length =
16835 ol.geom.flat.orient.orientLinearRings(
16836 this.orientedFlatCoordinates_, 0, this.ends_, this.stride);
16837 }
16838 this.orientedRevision_ = this.getRevision();
16839 }
16840 return this.orientedFlatCoordinates_;
16841};
16842
16843
16844/**
16845 * @inheritDoc
16846 */
16847ol.geom.Polygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
16848 var simplifiedFlatCoordinates = [];
16849 var simplifiedEnds = [];
16850 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizes(
16851 this.flatCoordinates, 0, this.ends_, this.stride,
16852 Math.sqrt(squaredTolerance),
16853 simplifiedFlatCoordinates, 0, simplifiedEnds);
16854 var simplifiedPolygon = new ol.geom.Polygon(null);
16855 simplifiedPolygon.setFlatCoordinates(
16856 ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
16857 return simplifiedPolygon;
16858};
16859
16860
16861/**
16862 * @inheritDoc
16863 * @api
16864 */
16865ol.geom.Polygon.prototype.getType = function() {
16866 return ol.geom.GeometryType.POLYGON;
16867};
16868
16869
16870/**
16871 * @inheritDoc
16872 * @api
16873 */
16874ol.geom.Polygon.prototype.intersectsExtent = function(extent) {
16875 return ol.geom.flat.intersectsextent.linearRings(
16876 this.getOrientedFlatCoordinates(), 0, this.ends_, this.stride, extent);
16877};
16878
16879
16880/**
16881 * Set the coordinates of the polygon.
16882 * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
16883 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
16884 * @override
16885 * @api
16886 */
16887ol.geom.Polygon.prototype.setCoordinates = function(coordinates, opt_layout) {
16888 if (!coordinates) {
16889 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
16890 } else {
16891 this.setLayout(opt_layout, coordinates, 2);
16892 if (!this.flatCoordinates) {
16893 this.flatCoordinates = [];
16894 }
16895 var ends = ol.geom.flat.deflate.coordinatess(
16896 this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
16897 this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
16898 this.changed();
16899 }
16900};
16901
16902
16903/**
16904 * @param {ol.geom.GeometryLayout} layout Layout.
16905 * @param {Array.<number>} flatCoordinates Flat coordinates.
16906 * @param {Array.<number>} ends Ends.
16907 */
16908ol.geom.Polygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {
16909 this.setFlatCoordinatesInternal(layout, flatCoordinates);
16910 this.ends_ = ends;
16911 this.changed();
16912};
16913
16914
16915/**
16916 * Create an approximation of a circle on the surface of a sphere.
16917 * @param {ol.Sphere} sphere The sphere.
16918 * @param {ol.Coordinate} center Center (`[lon, lat]` in degrees).
16919 * @param {number} radius The great-circle distance from the center to
16920 * the polygon vertices.
16921 * @param {number=} opt_n Optional number of vertices for the resulting
16922 * polygon. Default is `32`.
16923 * @return {ol.geom.Polygon} The "circular" polygon.
16924 * @api
16925 */
16926ol.geom.Polygon.circular = function(sphere, center, radius, opt_n) {
16927 var n = opt_n ? opt_n : 32;
16928 /** @type {Array.<number>} */
16929 var flatCoordinates = [];
16930 var i;
16931 for (i = 0; i < n; ++i) {
16932 ol.array.extend(
16933 flatCoordinates, sphere.offset(center, radius, 2 * Math.PI * i / n));
16934 }
16935 flatCoordinates.push(flatCoordinates[0], flatCoordinates[1]);
16936 var polygon = new ol.geom.Polygon(null);
16937 polygon.setFlatCoordinates(
16938 ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
16939 return polygon;
16940};
16941
16942
16943/**
16944 * Create a polygon from an extent. The layout used is `XY`.
16945 * @param {ol.Extent} extent The extent.
16946 * @return {ol.geom.Polygon} The polygon.
16947 * @api
16948 */
16949ol.geom.Polygon.fromExtent = function(extent) {
16950 var minX = extent[0];
16951 var minY = extent[1];
16952 var maxX = extent[2];
16953 var maxY = extent[3];
16954 var flatCoordinates =
16955 [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY];
16956 var polygon = new ol.geom.Polygon(null);
16957 polygon.setFlatCoordinates(
16958 ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
16959 return polygon;
16960};
16961
16962
16963/**
16964 * Create a regular polygon from a circle.
16965 * @param {ol.geom.Circle} circle Circle geometry.
16966 * @param {number=} opt_sides Number of sides of the polygon. Default is 32.
16967 * @param {number=} opt_angle Start angle for the first vertex of the polygon in
16968 * radians. Default is 0.
16969 * @return {ol.geom.Polygon} Polygon geometry.
16970 * @api
16971 */
16972ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) {
16973 var sides = opt_sides ? opt_sides : 32;
16974 var stride = circle.getStride();
16975 var layout = circle.getLayout();
16976 var polygon = new ol.geom.Polygon(null, layout);
16977 var arrayLength = stride * (sides + 1);
16978 var flatCoordinates = new Array(arrayLength);
16979 for (var i = 0; i < arrayLength; i++) {
16980 flatCoordinates[i] = 0;
16981 }
16982 var ends = [flatCoordinates.length];
16983 polygon.setFlatCoordinates(layout, flatCoordinates, ends);
16984 ol.geom.Polygon.makeRegular(
16985 polygon, circle.getCenter(), circle.getRadius(), opt_angle);
16986 return polygon;
16987};
16988
16989
16990/**
16991 * Modify the coordinates of a polygon to make it a regular polygon.
16992 * @param {ol.geom.Polygon} polygon Polygon geometry.
16993 * @param {ol.Coordinate} center Center of the regular polygon.
16994 * @param {number} radius Radius of the regular polygon.
16995 * @param {number=} opt_angle Start angle for the first vertex of the polygon in
16996 * radians. Default is 0.
16997 */
16998ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) {
16999 var flatCoordinates = polygon.getFlatCoordinates();
17000 var layout = polygon.getLayout();
17001 var stride = polygon.getStride();
17002 var ends = polygon.getEnds();
17003 var sides = flatCoordinates.length / stride - 1;
17004 var startAngle = opt_angle ? opt_angle : 0;
17005 var angle, offset;
17006 for (var i = 0; i <= sides; ++i) {
17007 offset = i * stride;
17008 angle = startAngle + (ol.math.modulo(i, sides) * 2 * Math.PI / sides);
17009 flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));
17010 flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));
17011 }
17012 polygon.setFlatCoordinates(layout, flatCoordinates, ends);
17013};
17014
17015goog.provide('ol.View');
17016
17017goog.require('ol');
17018goog.require('ol.CenterConstraint');
17019goog.require('ol.Object');
17020goog.require('ol.ResolutionConstraint');
17021goog.require('ol.RotationConstraint');
17022goog.require('ol.ViewHint');
17023goog.require('ol.ViewProperty');
17024goog.require('ol.array');
17025goog.require('ol.asserts');
17026goog.require('ol.coordinate');
17027goog.require('ol.easing');
17028goog.require('ol.extent');
17029goog.require('ol.geom.GeometryType');
17030goog.require('ol.geom.Polygon');
17031goog.require('ol.geom.SimpleGeometry');
17032goog.require('ol.math');
17033goog.require('ol.obj');
17034goog.require('ol.proj');
17035goog.require('ol.proj.Units');
17036
17037
17038/**
17039 * @classdesc
17040 * An ol.View object represents a simple 2D view of the map.
17041 *
17042 * This is the object to act upon to change the center, resolution,
17043 * and rotation of the map.
17044 *
17045 * ### The view states
17046 *
17047 * An `ol.View` is determined by three states: `center`, `resolution`,
17048 * and `rotation`. Each state has a corresponding getter and setter, e.g.
17049 * `getCenter` and `setCenter` for the `center` state.
17050 *
17051 * An `ol.View` has a `projection`. The projection determines the
17052 * coordinate system of the center, and its units determine the units of the
17053 * resolution (projection units per pixel). The default projection is
17054 * Spherical Mercator (EPSG:3857).
17055 *
17056 * ### The constraints
17057 *
17058 * `setCenter`, `setResolution` and `setRotation` can be used to change the
17059 * states of the view. Any value can be passed to the setters. And the value
17060 * that is passed to a setter will effectively be the value set in the view,
17061 * and returned by the corresponding getter.
17062 *
17063 * But an `ol.View` object also has a *resolution constraint*, a
17064 * *rotation constraint* and a *center constraint*.
17065 *
17066 * As said above, no constraints are applied when the setters are used to set
17067 * new states for the view. Applying constraints is done explicitly through
17068 * the use of the `constrain*` functions (`constrainResolution` and
17069 * `constrainRotation` and `constrainCenter`).
17070 *
17071 * The main users of the constraints are the interactions and the
17072 * controls. For example, double-clicking on the map changes the view to
17073 * the "next" resolution. And releasing the fingers after pinch-zooming
17074 * snaps to the closest resolution (with an animation).
17075 *
17076 * The *resolution constraint* snaps to specific resolutions. It is
17077 * determined by the following options: `resolutions`, `maxResolution`,
17078 * `maxZoom`, and `zoomFactor`. If `resolutions` is set, the other three
17079 * options are ignored. See documentation for each option for more
17080 * information.
17081 *
17082 * The *rotation constraint* snaps to specific angles. It is determined
17083 * by the following options: `enableRotation` and `constrainRotation`.
17084 * By default the rotation value is snapped to zero when approaching the
17085 * horizontal.
17086 *
17087 * The *center constraint* is determined by the `extent` option. By
17088 * default the center is not constrained at all.
17089 *
17090 * @constructor
17091 * @extends {ol.Object}
17092 * @param {olx.ViewOptions=} opt_options View options.
17093 * @api
17094 */
17095ol.View = function(opt_options) {
17096 ol.Object.call(this);
17097
17098 var options = ol.obj.assign({}, opt_options);
17099
17100 /**
17101 * @private
17102 * @type {Array.<number>}
17103 */
17104 this.hints_ = [0, 0];
17105
17106 /**
17107 * @private
17108 * @type {Array.<Array.<ol.ViewAnimation>>}
17109 */
17110 this.animations_ = [];
17111
17112 /**
17113 * @private
17114 * @type {number|undefined}
17115 */
17116 this.updateAnimationKey_;
17117
17118 this.updateAnimations_ = this.updateAnimations_.bind(this);
17119
17120 /**
17121 * @private
17122 * @const
17123 * @type {ol.proj.Projection}
17124 */
17125 this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857');
17126
17127 this.applyOptions_(options);
17128};
17129ol.inherits(ol.View, ol.Object);
17130
17131
17132/**
17133 * Set up the view with the given options.
17134 * @param {olx.ViewOptions} options View options.
17135 */
17136ol.View.prototype.applyOptions_ = function(options) {
17137
17138 /**
17139 * @type {Object.<string, *>}
17140 */
17141 var properties = {};
17142 properties[ol.ViewProperty.CENTER] = options.center !== undefined ?
17143 options.center : null;
17144
17145 var resolutionConstraintInfo = ol.View.createResolutionConstraint_(
17146 options);
17147
17148 /**
17149 * @private
17150 * @type {number}
17151 */
17152 this.maxResolution_ = resolutionConstraintInfo.maxResolution;
17153
17154 /**
17155 * @private
17156 * @type {number}
17157 */
17158 this.minResolution_ = resolutionConstraintInfo.minResolution;
17159
17160 /**
17161 * @private
17162 * @type {number}
17163 */
17164 this.zoomFactor_ = resolutionConstraintInfo.zoomFactor;
17165
17166 /**
17167 * @private
17168 * @type {Array.<number>|undefined}
17169 */
17170 this.resolutions_ = options.resolutions;
17171
17172 /**
17173 * @private
17174 * @type {number}
17175 */
17176 this.minZoom_ = resolutionConstraintInfo.minZoom;
17177
17178 var centerConstraint = ol.View.createCenterConstraint_(options);
17179 var resolutionConstraint = resolutionConstraintInfo.constraint;
17180 var rotationConstraint = ol.View.createRotationConstraint_(options);
17181
17182 /**
17183 * @private
17184 * @type {ol.Constraints}
17185 */
17186 this.constraints_ = {
17187 center: centerConstraint,
17188 resolution: resolutionConstraint,
17189 rotation: rotationConstraint
17190 };
17191
17192 if (options.resolution !== undefined) {
17193 properties[ol.ViewProperty.RESOLUTION] = options.resolution;
17194 } else if (options.zoom !== undefined) {
17195 properties[ol.ViewProperty.RESOLUTION] = this.constrainResolution(
17196 this.maxResolution_, options.zoom - this.minZoom_);
17197 }
17198 properties[ol.ViewProperty.ROTATION] =
17199 options.rotation !== undefined ? options.rotation : 0;
17200 this.setProperties(properties);
17201
17202 /**
17203 * @private
17204 * @type {olx.ViewOptions}
17205 */
17206 this.options_ = options;
17207
17208};
17209
17210/**
17211 * Get an updated version of the view options used to construct the view. The
17212 * current resolution (or zoom), center, and rotation are applied to any stored
17213 * options. The provided options can be uesd to apply new min/max zoom or
17214 * resolution limits.
17215 * @param {olx.ViewOptions} newOptions New options to be applied.
17216 * @return {olx.ViewOptions} New options updated with the current view state.
17217 */
17218ol.View.prototype.getUpdatedOptions_ = function(newOptions) {
17219 var options = ol.obj.assign({}, this.options_);
17220
17221 // preserve resolution (or zoom)
17222 if (options.resolution !== undefined) {
17223 options.resolution = this.getResolution();
17224 } else {
17225 options.zoom = this.getZoom();
17226 }
17227
17228 // preserve center
17229 options.center = this.getCenter();
17230
17231 // preserve rotation
17232 options.rotation = this.getRotation();
17233
17234 return ol.obj.assign({}, options, newOptions);
17235};
17236
17237
17238/**
17239 * Animate the view. The view's center, zoom (or resolution), and rotation
17240 * can be animated for smooth transitions between view states. For example,
17241 * to animate the view to a new zoom level:
17242 *
17243 * view.animate({zoom: view.getZoom() + 1});
17244 *
17245 * By default, the animation lasts one second and uses in-and-out easing. You
17246 * can customize this behavior by including `duration` (in milliseconds) and
17247 * `easing` options (see {@link ol.easing}).
17248 *
17249 * To chain together multiple animations, call the method with multiple
17250 * animation objects. For example, to first zoom and then pan:
17251 *
17252 * view.animate({zoom: 10}, {center: [0, 0]});
17253 *
17254 * If you provide a function as the last argument to the animate method, it
17255 * will get called at the end of an animation series. The callback will be
17256 * called with `true` if the animation series completed on its own or `false`
17257 * if it was cancelled.
17258 *
17259 * Animations are cancelled by user interactions (e.g. dragging the map) or by
17260 * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()`
17261 * (or another method that calls one of these).
17262 *
17263 * @param {...(olx.AnimationOptions|function(boolean))} var_args Animation
17264 * options. Multiple animations can be run in series by passing multiple
17265 * options objects. To run multiple animations in parallel, call the method
17266 * multiple times. An optional callback can be provided as a final
17267 * argument. The callback will be called with a boolean indicating whether
17268 * the animation completed without being cancelled.
17269 * @api
17270 */
17271ol.View.prototype.animate = function(var_args) {
17272 var start = Date.now();
17273 var center = this.getCenter().slice();
17274 var resolution = this.getResolution();
17275 var rotation = this.getRotation();
17276 var animationCount = arguments.length;
17277 var callback;
17278 if (animationCount > 1 && typeof arguments[animationCount - 1] === 'function') {
17279 callback = arguments[animationCount - 1];
17280 --animationCount;
17281 }
17282 var series = [];
17283 for (var i = 0; i < animationCount; ++i) {
17284 var options = /** @type {olx.AnimationOptions} */ (arguments[i]);
17285
17286 var animation = /** @type {ol.ViewAnimation} */ ({
17287 start: start,
17288 complete: false,
17289 anchor: options.anchor,
17290 duration: options.duration !== undefined ? options.duration : 1000,
17291 easing: options.easing || ol.easing.inAndOut
17292 });
17293
17294 if (options.center) {
17295 animation.sourceCenter = center;
17296 animation.targetCenter = options.center;
17297 center = animation.targetCenter;
17298 }
17299
17300 if (options.zoom !== undefined) {
17301 animation.sourceResolution = resolution;
17302 animation.targetResolution = this.constrainResolution(
17303 this.maxResolution_, options.zoom - this.minZoom_, 0);
17304 resolution = animation.targetResolution;
17305 } else if (options.resolution) {
17306 animation.sourceResolution = resolution;
17307 animation.targetResolution = options.resolution;
17308 resolution = animation.targetResolution;
17309 }
17310
17311 if (options.rotation !== undefined) {
17312 animation.sourceRotation = rotation;
17313 var delta = ol.math.modulo(options.rotation - rotation + Math.PI, 2 * Math.PI) - Math.PI;
17314 animation.targetRotation = rotation + delta;
17315 rotation = animation.targetRotation;
17316 }
17317
17318 animation.callback = callback;
17319
17320 // check if animation is a no-op
17321 if (ol.View.isNoopAnimation(animation)) {
17322 animation.complete = true;
17323 // we still push it onto the series for callback handling
17324 } else {
17325 start += animation.duration;
17326 }
17327 series.push(animation);
17328 }
17329 this.animations_.push(series);
17330 this.setHint(ol.ViewHint.ANIMATING, 1);
17331 this.updateAnimations_();
17332};
17333
17334
17335/**
17336 * Determine if the view is being animated.
17337 * @return {boolean} The view is being animated.
17338 * @api
17339 */
17340ol.View.prototype.getAnimating = function() {
17341 return this.getHints()[ol.ViewHint.ANIMATING] > 0;
17342};
17343
17344
17345/**
17346 * Determine if the user is interacting with the view, such as panning or zooming.
17347 * @return {boolean} The view is being interacted with.
17348 * @api
17349 */
17350ol.View.prototype.getInteracting = function() {
17351 return this.getHints()[ol.ViewHint.INTERACTING] > 0;
17352};
17353
17354
17355/**
17356 * Cancel any ongoing animations.
17357 * @api
17358 */
17359ol.View.prototype.cancelAnimations = function() {
17360 this.setHint(ol.ViewHint.ANIMATING, -this.getHints()[ol.ViewHint.ANIMATING]);
17361 for (var i = 0, ii = this.animations_.length; i < ii; ++i) {
17362 var series = this.animations_[i];
17363 if (series[0].callback) {
17364 series[0].callback(false);
17365 }
17366 }
17367 this.animations_.length = 0;
17368};
17369
17370/**
17371 * Update all animations.
17372 */
17373ol.View.prototype.updateAnimations_ = function() {
17374 if (this.updateAnimationKey_ !== undefined) {
17375 cancelAnimationFrame(this.updateAnimationKey_);
17376 this.updateAnimationKey_ = undefined;
17377 }
17378 if (!this.getAnimating()) {
17379 return;
17380 }
17381 var now = Date.now();
17382 var more = false;
17383 for (var i = this.animations_.length - 1; i >= 0; --i) {
17384 var series = this.animations_[i];
17385 var seriesComplete = true;
17386 for (var j = 0, jj = series.length; j < jj; ++j) {
17387 var animation = series[j];
17388 if (animation.complete) {
17389 continue;
17390 }
17391 var elapsed = now - animation.start;
17392 var fraction = animation.duration > 0 ? elapsed / animation.duration : 1;
17393 if (fraction >= 1) {
17394 animation.complete = true;
17395 fraction = 1;
17396 } else {
17397 seriesComplete = false;
17398 }
17399 var progress = animation.easing(fraction);
17400 if (animation.sourceCenter) {
17401 var x0 = animation.sourceCenter[0];
17402 var y0 = animation.sourceCenter[1];
17403 var x1 = animation.targetCenter[0];
17404 var y1 = animation.targetCenter[1];
17405 var x = x0 + progress * (x1 - x0);
17406 var y = y0 + progress * (y1 - y0);
17407 this.set(ol.ViewProperty.CENTER, [x, y]);
17408 }
17409 if (animation.sourceResolution && animation.targetResolution) {
17410 var resolution = progress === 1 ?
17411 animation.targetResolution :
17412 animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
17413 if (animation.anchor) {
17414 this.set(ol.ViewProperty.CENTER,
17415 this.calculateCenterZoom(resolution, animation.anchor));
17416 }
17417 this.set(ol.ViewProperty.RESOLUTION, resolution);
17418 }
17419 if (animation.sourceRotation !== undefined && animation.targetRotation !== undefined) {
17420 var rotation = progress === 1 ?
17421 ol.math.modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI :
17422 animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation);
17423 if (animation.anchor) {
17424 this.set(ol.ViewProperty.CENTER,
17425 this.calculateCenterRotate(rotation, animation.anchor));
17426 }
17427 this.set(ol.ViewProperty.ROTATION, rotation);
17428 }
17429 more = true;
17430 if (!animation.complete) {
17431 break;
17432 }
17433 }
17434 if (seriesComplete) {
17435 this.animations_[i] = null;
17436 this.setHint(ol.ViewHint.ANIMATING, -1);
17437 var callback = series[0].callback;
17438 if (callback) {
17439 callback(true);
17440 }
17441 }
17442 }
17443 // prune completed series
17444 this.animations_ = this.animations_.filter(Boolean);
17445 if (more && this.updateAnimationKey_ === undefined) {
17446 this.updateAnimationKey_ = requestAnimationFrame(this.updateAnimations_);
17447 }
17448};
17449
17450/**
17451 * @param {number} rotation Target rotation.
17452 * @param {ol.Coordinate} anchor Rotation anchor.
17453 * @return {ol.Coordinate|undefined} Center for rotation and anchor.
17454 */
17455ol.View.prototype.calculateCenterRotate = function(rotation, anchor) {
17456 var center;
17457 var currentCenter = this.getCenter();
17458 if (currentCenter !== undefined) {
17459 center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]];
17460 ol.coordinate.rotate(center, rotation - this.getRotation());
17461 ol.coordinate.add(center, anchor);
17462 }
17463 return center;
17464};
17465
17466
17467/**
17468 * @param {number} resolution Target resolution.
17469 * @param {ol.Coordinate} anchor Zoom anchor.
17470 * @return {ol.Coordinate|undefined} Center for resolution and anchor.
17471 */
17472ol.View.prototype.calculateCenterZoom = function(resolution, anchor) {
17473 var center;
17474 var currentCenter = this.getCenter();
17475 var currentResolution = this.getResolution();
17476 if (currentCenter !== undefined && currentResolution !== undefined) {
17477 var x = anchor[0] -
17478 resolution * (anchor[0] - currentCenter[0]) / currentResolution;
17479 var y = anchor[1] -
17480 resolution * (anchor[1] - currentCenter[1]) / currentResolution;
17481 center = [x, y];
17482 }
17483 return center;
17484};
17485
17486
17487/**
17488 * @private
17489 * @return {ol.Size} Viewport size or `[100, 100]` when no viewport is found.
17490 */
17491ol.View.prototype.getSizeFromViewport_ = function() {
17492 var size = [100, 100];
17493 var selector = '.ol-viewport[data-view="' + ol.getUid(this) + '"]';
17494 var element = document.querySelector(selector);
17495 if (element) {
17496 var metrics = getComputedStyle(element);
17497 size[0] = parseInt(metrics.width, 10);
17498 size[1] = parseInt(metrics.height, 10);
17499 }
17500 return size;
17501};
17502
17503
17504/**
17505 * Get the constrained center of this view.
17506 * @param {ol.Coordinate|undefined} center Center.
17507 * @return {ol.Coordinate|undefined} Constrained center.
17508 * @api
17509 */
17510ol.View.prototype.constrainCenter = function(center) {
17511 return this.constraints_.center(center);
17512};
17513
17514
17515/**
17516 * Get the constrained resolution of this view.
17517 * @param {number|undefined} resolution Resolution.
17518 * @param {number=} opt_delta Delta. Default is `0`.
17519 * @param {number=} opt_direction Direction. Default is `0`.
17520 * @return {number|undefined} Constrained resolution.
17521 * @api
17522 */
17523ol.View.prototype.constrainResolution = function(
17524 resolution, opt_delta, opt_direction) {
17525 var delta = opt_delta || 0;
17526 var direction = opt_direction || 0;
17527 return this.constraints_.resolution(resolution, delta, direction);
17528};
17529
17530
17531/**
17532 * Get the constrained rotation of this view.
17533 * @param {number|undefined} rotation Rotation.
17534 * @param {number=} opt_delta Delta. Default is `0`.
17535 * @return {number|undefined} Constrained rotation.
17536 * @api
17537 */
17538ol.View.prototype.constrainRotation = function(rotation, opt_delta) {
17539 var delta = opt_delta || 0;
17540 return this.constraints_.rotation(rotation, delta);
17541};
17542
17543
17544/**
17545 * Get the view center.
17546 * @return {ol.Coordinate|undefined} The center of the view.
17547 * @observable
17548 * @api
17549 */
17550ol.View.prototype.getCenter = function() {
17551 return /** @type {ol.Coordinate|undefined} */ (
17552 this.get(ol.ViewProperty.CENTER));
17553};
17554
17555
17556/**
17557 * @return {ol.Constraints} Constraints.
17558 */
17559ol.View.prototype.getConstraints = function() {
17560 return this.constraints_;
17561};
17562
17563
17564/**
17565 * @param {Array.<number>=} opt_hints Destination array.
17566 * @return {Array.<number>} Hint.
17567 */
17568ol.View.prototype.getHints = function(opt_hints) {
17569 if (opt_hints !== undefined) {
17570 opt_hints[0] = this.hints_[0];
17571 opt_hints[1] = this.hints_[1];
17572 return opt_hints;
17573 } else {
17574 return this.hints_.slice();
17575 }
17576};
17577
17578
17579/**
17580 * Calculate the extent for the current view state and the passed size.
17581 * The size is the pixel dimensions of the box into which the calculated extent
17582 * should fit. In most cases you want to get the extent of the entire map,
17583 * that is `map.getSize()`.
17584 * @param {ol.Size=} opt_size Box pixel size. If not provided, the size of the
17585 * first map that uses this view will be used.
17586 * @return {ol.Extent} Extent.
17587 * @api
17588 */
17589ol.View.prototype.calculateExtent = function(opt_size) {
17590 var size = opt_size || this.getSizeFromViewport_();
17591 var center = /** @type {!ol.Coordinate} */ (this.getCenter());
17592 ol.asserts.assert(center, 1); // The view center is not defined
17593 var resolution = /** @type {!number} */ (this.getResolution());
17594 ol.asserts.assert(resolution !== undefined, 2); // The view resolution is not defined
17595 var rotation = /** @type {!number} */ (this.getRotation());
17596 ol.asserts.assert(rotation !== undefined, 3); // The view rotation is not defined
17597
17598 return ol.extent.getForViewAndSize(center, resolution, rotation, size);
17599};
17600
17601
17602/**
17603 * Get the maximum resolution of the view.
17604 * @return {number} The maximum resolution of the view.
17605 * @api
17606 */
17607ol.View.prototype.getMaxResolution = function() {
17608 return this.maxResolution_;
17609};
17610
17611
17612/**
17613 * Get the minimum resolution of the view.
17614 * @return {number} The minimum resolution of the view.
17615 * @api
17616 */
17617ol.View.prototype.getMinResolution = function() {
17618 return this.minResolution_;
17619};
17620
17621
17622/**
17623 * Get the maximum zoom level for the view.
17624 * @return {number} The maximum zoom level.
17625 * @api
17626 */
17627ol.View.prototype.getMaxZoom = function() {
17628 return /** @type {number} */ (this.getZoomForResolution(this.minResolution_));
17629};
17630
17631
17632/**
17633 * Set a new maximum zoom level for the view.
17634 * @param {number} zoom The maximum zoom level.
17635 * @api
17636 */
17637ol.View.prototype.setMaxZoom = function(zoom) {
17638 this.applyOptions_(this.getUpdatedOptions_({maxZoom: zoom}));
17639};
17640
17641
17642/**
17643 * Get the minimum zoom level for the view.
17644 * @return {number} The minimum zoom level.
17645 * @api
17646 */
17647ol.View.prototype.getMinZoom = function() {
17648 return /** @type {number} */ (this.getZoomForResolution(this.maxResolution_));
17649};
17650
17651
17652/**
17653 * Set a new minimum zoom level for the view.
17654 * @param {number} zoom The minimum zoom level.
17655 * @api
17656 */
17657ol.View.prototype.setMinZoom = function(zoom) {
17658 this.applyOptions_(this.getUpdatedOptions_({minZoom: zoom}));
17659};
17660
17661
17662/**
17663 * Get the view projection.
17664 * @return {ol.proj.Projection} The projection of the view.
17665 * @api
17666 */
17667ol.View.prototype.getProjection = function() {
17668 return this.projection_;
17669};
17670
17671
17672/**
17673 * Get the view resolution.
17674 * @return {number|undefined} The resolution of the view.
17675 * @observable
17676 * @api
17677 */
17678ol.View.prototype.getResolution = function() {
17679 return /** @type {number|undefined} */ (
17680 this.get(ol.ViewProperty.RESOLUTION));
17681};
17682
17683
17684/**
17685 * Get the resolutions for the view. This returns the array of resolutions
17686 * passed to the constructor of the {ol.View}, or undefined if none were given.
17687 * @return {Array.<number>|undefined} The resolutions of the view.
17688 * @api
17689 */
17690ol.View.prototype.getResolutions = function() {
17691 return this.resolutions_;
17692};
17693
17694
17695/**
17696 * Get the resolution for a provided extent (in map units) and size (in pixels).
17697 * @param {ol.Extent} extent Extent.
17698 * @param {ol.Size=} opt_size Box pixel size.
17699 * @return {number} The resolution at which the provided extent will render at
17700 * the given size.
17701 * @api
17702 */
17703ol.View.prototype.getResolutionForExtent = function(extent, opt_size) {
17704 var size = opt_size || this.getSizeFromViewport_();
17705 var xResolution = ol.extent.getWidth(extent) / size[0];
17706 var yResolution = ol.extent.getHeight(extent) / size[1];
17707 return Math.max(xResolution, yResolution);
17708};
17709
17710
17711/**
17712 * Return a function that returns a value between 0 and 1 for a
17713 * resolution. Exponential scaling is assumed.
17714 * @param {number=} opt_power Power.
17715 * @return {function(number): number} Resolution for value function.
17716 */
17717ol.View.prototype.getResolutionForValueFunction = function(opt_power) {
17718 var power = opt_power || 2;
17719 var maxResolution = this.maxResolution_;
17720 var minResolution = this.minResolution_;
17721 var max = Math.log(maxResolution / minResolution) / Math.log(power);
17722 return (
17723 /**
17724 * @param {number} value Value.
17725 * @return {number} Resolution.
17726 */
17727 function(value) {
17728 var resolution = maxResolution / Math.pow(power, value * max);
17729 return resolution;
17730 });
17731};
17732
17733
17734/**
17735 * Get the view rotation.
17736 * @return {number} The rotation of the view in radians.
17737 * @observable
17738 * @api
17739 */
17740ol.View.prototype.getRotation = function() {
17741 return /** @type {number} */ (this.get(ol.ViewProperty.ROTATION));
17742};
17743
17744
17745/**
17746 * Return a function that returns a resolution for a value between
17747 * 0 and 1. Exponential scaling is assumed.
17748 * @param {number=} opt_power Power.
17749 * @return {function(number): number} Value for resolution function.
17750 */
17751ol.View.prototype.getValueForResolutionFunction = function(opt_power) {
17752 var power = opt_power || 2;
17753 var maxResolution = this.maxResolution_;
17754 var minResolution = this.minResolution_;
17755 var max = Math.log(maxResolution / minResolution) / Math.log(power);
17756 return (
17757 /**
17758 * @param {number} resolution Resolution.
17759 * @return {number} Value.
17760 */
17761 function(resolution) {
17762 var value =
17763 (Math.log(maxResolution / resolution) / Math.log(power)) / max;
17764 return value;
17765 });
17766};
17767
17768
17769/**
17770 * @return {olx.ViewState} View state.
17771 */
17772ol.View.prototype.getState = function() {
17773 var center = /** @type {ol.Coordinate} */ (this.getCenter());
17774 var projection = this.getProjection();
17775 var resolution = /** @type {number} */ (this.getResolution());
17776 var rotation = this.getRotation();
17777 return /** @type {olx.ViewState} */ ({
17778 center: center.slice(),
17779 projection: projection !== undefined ? projection : null,
17780 resolution: resolution,
17781 rotation: rotation
17782 });
17783};
17784
17785
17786/**
17787 * Get the current zoom level. Return undefined if the current
17788 * resolution is undefined or not within the "resolution constraints".
17789 * @return {number|undefined} Zoom.
17790 * @api
17791 */
17792ol.View.prototype.getZoom = function() {
17793 var zoom;
17794 var resolution = this.getResolution();
17795 if (resolution !== undefined) {
17796 zoom = this.getZoomForResolution(resolution);
17797 }
17798 return zoom;
17799};
17800
17801
17802/**
17803 * Get the zoom level for a resolution.
17804 * @param {number} resolution The resolution.
17805 * @return {number|undefined} The zoom level for the provided resolution.
17806 * @api
17807 */
17808ol.View.prototype.getZoomForResolution = function(resolution) {
17809 var zoom;
17810 if (resolution >= this.minResolution_ && resolution <= this.maxResolution_) {
17811 var offset = this.minZoom_ || 0;
17812 var max, zoomFactor;
17813 if (this.resolutions_) {
17814 var nearest = ol.array.linearFindNearest(this.resolutions_, resolution, 1);
17815 offset += nearest;
17816 if (nearest == this.resolutions_.length - 1) {
17817 return offset;
17818 }
17819 max = this.resolutions_[nearest];
17820 zoomFactor = max / this.resolutions_[nearest + 1];
17821 } else {
17822 max = this.maxResolution_;
17823 zoomFactor = this.zoomFactor_;
17824 }
17825 zoom = offset + Math.log(max / resolution) / Math.log(zoomFactor);
17826 }
17827 return zoom;
17828};
17829
17830
17831/**
17832 * Get the resolution for a zoom level.
17833 * @param {number} zoom Zoom level.
17834 * @return {number} The view resolution for the provided zoom level.
17835 * @api
17836 */
17837ol.View.prototype.getResolutionForZoom = function(zoom) {
17838 return /** @type {number} */ (this.constrainResolution(
17839 this.maxResolution_, zoom - this.minZoom_, 0));
17840};
17841
17842
17843/**
17844 * Fit the given geometry or extent based on the given map size and border.
17845 * The size is pixel dimensions of the box to fit the extent into.
17846 * In most cases you will want to use the map size, that is `map.getSize()`.
17847 * Takes care of the map angle.
17848 * @param {ol.geom.SimpleGeometry|ol.Extent} geometryOrExtent The geometry or
17849 * extent to fit the view to.
17850 * @param {olx.view.FitOptions=} opt_options Options.
17851 * @api
17852 */
17853ol.View.prototype.fit = function(geometryOrExtent, opt_options) {
17854 var options = opt_options || {};
17855 var size = options.size;
17856 if (!size) {
17857 size = this.getSizeFromViewport_();
17858 }
17859 /** @type {ol.geom.SimpleGeometry} */
17860 var geometry;
17861 if (!(geometryOrExtent instanceof ol.geom.SimpleGeometry)) {
17862 ol.asserts.assert(Array.isArray(geometryOrExtent),
17863 24); // Invalid extent or geometry provided as `geometry`
17864 ol.asserts.assert(!ol.extent.isEmpty(geometryOrExtent),
17865 25); // Cannot fit empty extent provided as `geometry`
17866 geometry = ol.geom.Polygon.fromExtent(geometryOrExtent);
17867 } else if (geometryOrExtent.getType() === ol.geom.GeometryType.CIRCLE) {
17868 geometryOrExtent = geometryOrExtent.getExtent();
17869 geometry = ol.geom.Polygon.fromExtent(geometryOrExtent);
17870 geometry.rotate(this.getRotation(), ol.extent.getCenter(geometryOrExtent));
17871 } else {
17872 geometry = geometryOrExtent;
17873 }
17874
17875 var padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
17876 var constrainResolution = options.constrainResolution !== undefined ?
17877 options.constrainResolution : true;
17878 var nearest = options.nearest !== undefined ? options.nearest : false;
17879 var minResolution;
17880 if (options.minResolution !== undefined) {
17881 minResolution = options.minResolution;
17882 } else if (options.maxZoom !== undefined) {
17883 minResolution = this.constrainResolution(
17884 this.maxResolution_, options.maxZoom - this.minZoom_, 0);
17885 } else {
17886 minResolution = 0;
17887 }
17888 var coords = geometry.getFlatCoordinates();
17889
17890 // calculate rotated extent
17891 var rotation = this.getRotation();
17892 var cosAngle = Math.cos(-rotation);
17893 var sinAngle = Math.sin(-rotation);
17894 var minRotX = +Infinity;
17895 var minRotY = +Infinity;
17896 var maxRotX = -Infinity;
17897 var maxRotY = -Infinity;
17898 var stride = geometry.getStride();
17899 for (var i = 0, ii = coords.length; i < ii; i += stride) {
17900 var rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle;
17901 var rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle;
17902 minRotX = Math.min(minRotX, rotX);
17903 minRotY = Math.min(minRotY, rotY);
17904 maxRotX = Math.max(maxRotX, rotX);
17905 maxRotY = Math.max(maxRotY, rotY);
17906 }
17907
17908 // calculate resolution
17909 var resolution = this.getResolutionForExtent(
17910 [minRotX, minRotY, maxRotX, maxRotY],
17911 [size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2]]);
17912 resolution = isNaN(resolution) ? minResolution :
17913 Math.max(resolution, minResolution);
17914 if (constrainResolution) {
17915 var constrainedResolution = this.constrainResolution(resolution, 0, 0);
17916 if (!nearest && constrainedResolution < resolution) {
17917 constrainedResolution = this.constrainResolution(
17918 constrainedResolution, -1, 0);
17919 }
17920 resolution = constrainedResolution;
17921 }
17922
17923 // calculate center
17924 sinAngle = -sinAngle; // go back to original rotation
17925 var centerRotX = (minRotX + maxRotX) / 2;
17926 var centerRotY = (minRotY + maxRotY) / 2;
17927 centerRotX += (padding[1] - padding[3]) / 2 * resolution;
17928 centerRotY += (padding[0] - padding[2]) / 2 * resolution;
17929 var centerX = centerRotX * cosAngle - centerRotY * sinAngle;
17930 var centerY = centerRotY * cosAngle + centerRotX * sinAngle;
17931 var center = [centerX, centerY];
17932 var callback = options.callback ? options.callback : ol.nullFunction;
17933
17934 if (options.duration !== undefined) {
17935 this.animate({
17936 resolution: resolution,
17937 center: center,
17938 duration: options.duration,
17939 easing: options.easing
17940 }, callback);
17941 } else {
17942 this.setResolution(resolution);
17943 this.setCenter(center);
17944 setTimeout(callback.bind(undefined, true), 0);
17945 }
17946};
17947
17948
17949/**
17950 * Center on coordinate and view position.
17951 * @param {ol.Coordinate} coordinate Coordinate.
17952 * @param {ol.Size} size Box pixel size.
17953 * @param {ol.Pixel} position Position on the view to center on.
17954 * @api
17955 */
17956ol.View.prototype.centerOn = function(coordinate, size, position) {
17957 // calculate rotated position
17958 var rotation = this.getRotation();
17959 var cosAngle = Math.cos(-rotation);
17960 var sinAngle = Math.sin(-rotation);
17961 var rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle;
17962 var rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle;
17963 var resolution = this.getResolution();
17964 rotX += (size[0] / 2 - position[0]) * resolution;
17965 rotY += (position[1] - size[1] / 2) * resolution;
17966
17967 // go back to original angle
17968 sinAngle = -sinAngle; // go back to original rotation
17969 var centerX = rotX * cosAngle - rotY * sinAngle;
17970 var centerY = rotY * cosAngle + rotX * sinAngle;
17971
17972 this.setCenter([centerX, centerY]);
17973};
17974
17975
17976/**
17977 * @return {boolean} Is defined.
17978 */
17979ol.View.prototype.isDef = function() {
17980 return !!this.getCenter() && this.getResolution() !== undefined;
17981};
17982
17983
17984/**
17985 * Rotate the view around a given coordinate.
17986 * @param {number} rotation New rotation value for the view.
17987 * @param {ol.Coordinate=} opt_anchor The rotation center.
17988 * @api
17989 */
17990ol.View.prototype.rotate = function(rotation, opt_anchor) {
17991 if (opt_anchor !== undefined) {
17992 var center = this.calculateCenterRotate(rotation, opt_anchor);
17993 this.setCenter(center);
17994 }
17995 this.setRotation(rotation);
17996};
17997
17998
17999/**
18000 * Set the center of the current view.
18001 * @param {ol.Coordinate|undefined} center The center of the view.
18002 * @observable
18003 * @api
18004 */
18005ol.View.prototype.setCenter = function(center) {
18006 this.set(ol.ViewProperty.CENTER, center);
18007 if (this.getAnimating()) {
18008 this.cancelAnimations();
18009 }
18010};
18011
18012
18013/**
18014 * @param {ol.ViewHint} hint Hint.
18015 * @param {number} delta Delta.
18016 * @return {number} New value.
18017 */
18018ol.View.prototype.setHint = function(hint, delta) {
18019 this.hints_[hint] += delta;
18020 this.changed();
18021 return this.hints_[hint];
18022};
18023
18024
18025/**
18026 * Set the resolution for this view.
18027 * @param {number|undefined} resolution The resolution of the view.
18028 * @observable
18029 * @api
18030 */
18031ol.View.prototype.setResolution = function(resolution) {
18032 this.set(ol.ViewProperty.RESOLUTION, resolution);
18033 if (this.getAnimating()) {
18034 this.cancelAnimations();
18035 }
18036};
18037
18038
18039/**
18040 * Set the rotation for this view.
18041 * @param {number} rotation The rotation of the view in radians.
18042 * @observable
18043 * @api
18044 */
18045ol.View.prototype.setRotation = function(rotation) {
18046 this.set(ol.ViewProperty.ROTATION, rotation);
18047 if (this.getAnimating()) {
18048 this.cancelAnimations();
18049 }
18050};
18051
18052
18053/**
18054 * Zoom to a specific zoom level.
18055 * @param {number} zoom Zoom level.
18056 * @api
18057 */
18058ol.View.prototype.setZoom = function(zoom) {
18059 this.setResolution(this.getResolutionForZoom(zoom));
18060};
18061
18062
18063/**
18064 * @param {olx.ViewOptions} options View options.
18065 * @private
18066 * @return {ol.CenterConstraintType} The constraint.
18067 */
18068ol.View.createCenterConstraint_ = function(options) {
18069 if (options.extent !== undefined) {
18070 return ol.CenterConstraint.createExtent(options.extent);
18071 } else {
18072 return ol.CenterConstraint.none;
18073 }
18074};
18075
18076
18077/**
18078 * @private
18079 * @param {olx.ViewOptions} options View options.
18080 * @return {{constraint: ol.ResolutionConstraintType, maxResolution: number,
18081 * minResolution: number, zoomFactor: number}} The constraint.
18082 */
18083ol.View.createResolutionConstraint_ = function(options) {
18084 var resolutionConstraint;
18085 var maxResolution;
18086 var minResolution;
18087
18088 // TODO: move these to be ol constants
18089 // see https://github.com/openlayers/openlayers/issues/2076
18090 var defaultMaxZoom = 28;
18091 var defaultZoomFactor = 2;
18092
18093 var minZoom = options.minZoom !== undefined ?
18094 options.minZoom : ol.DEFAULT_MIN_ZOOM;
18095
18096 var maxZoom = options.maxZoom !== undefined ?
18097 options.maxZoom : defaultMaxZoom;
18098
18099 var zoomFactor = options.zoomFactor !== undefined ?
18100 options.zoomFactor : defaultZoomFactor;
18101
18102 if (options.resolutions !== undefined) {
18103 var resolutions = options.resolutions;
18104 maxResolution = resolutions[0];
18105 minResolution = resolutions[resolutions.length - 1];
18106 resolutionConstraint = ol.ResolutionConstraint.createSnapToResolutions(
18107 resolutions);
18108 } else {
18109 // calculate the default min and max resolution
18110 var projection = ol.proj.createProjection(options.projection, 'EPSG:3857');
18111 var extent = projection.getExtent();
18112 var size = !extent ?
18113 // use an extent that can fit the whole world if need be
18114 360 * ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES] /
18115 projection.getMetersPerUnit() :
18116 Math.max(ol.extent.getWidth(extent), ol.extent.getHeight(extent));
18117
18118 var defaultMaxResolution = size / ol.DEFAULT_TILE_SIZE / Math.pow(
18119 defaultZoomFactor, ol.DEFAULT_MIN_ZOOM);
18120
18121 var defaultMinResolution = defaultMaxResolution / Math.pow(
18122 defaultZoomFactor, defaultMaxZoom - ol.DEFAULT_MIN_ZOOM);
18123
18124 // user provided maxResolution takes precedence
18125 maxResolution = options.maxResolution;
18126 if (maxResolution !== undefined) {
18127 minZoom = 0;
18128 } else {
18129 maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom);
18130 }
18131
18132 // user provided minResolution takes precedence
18133 minResolution = options.minResolution;
18134 if (minResolution === undefined) {
18135 if (options.maxZoom !== undefined) {
18136 if (options.maxResolution !== undefined) {
18137 minResolution = maxResolution / Math.pow(zoomFactor, maxZoom);
18138 } else {
18139 minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom);
18140 }
18141 } else {
18142 minResolution = defaultMinResolution;
18143 }
18144 }
18145
18146 // given discrete zoom levels, minResolution may be different than provided
18147 maxZoom = minZoom + Math.floor(
18148 Math.log(maxResolution / minResolution) / Math.log(zoomFactor));
18149 minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom);
18150
18151 resolutionConstraint = ol.ResolutionConstraint.createSnapToPower(
18152 zoomFactor, maxResolution, maxZoom - minZoom);
18153 }
18154 return {constraint: resolutionConstraint, maxResolution: maxResolution,
18155 minResolution: minResolution, minZoom: minZoom, zoomFactor: zoomFactor};
18156};
18157
18158
18159/**
18160 * @private
18161 * @param {olx.ViewOptions} options View options.
18162 * @return {ol.RotationConstraintType} Rotation constraint.
18163 */
18164ol.View.createRotationConstraint_ = function(options) {
18165 var enableRotation = options.enableRotation !== undefined ?
18166 options.enableRotation : true;
18167 if (enableRotation) {
18168 var constrainRotation = options.constrainRotation;
18169 if (constrainRotation === undefined || constrainRotation === true) {
18170 return ol.RotationConstraint.createSnapToZero();
18171 } else if (constrainRotation === false) {
18172 return ol.RotationConstraint.none;
18173 } else if (typeof constrainRotation === 'number') {
18174 return ol.RotationConstraint.createSnapToN(constrainRotation);
18175 } else {
18176 return ol.RotationConstraint.none;
18177 }
18178 } else {
18179 return ol.RotationConstraint.disable;
18180 }
18181};
18182
18183
18184/**
18185 * Determine if an animation involves no view change.
18186 * @param {ol.ViewAnimation} animation The animation.
18187 * @return {boolean} The animation involves no view change.
18188 */
18189ol.View.isNoopAnimation = function(animation) {
18190 if (animation.sourceCenter && animation.targetCenter) {
18191 if (!ol.coordinate.equals(animation.sourceCenter, animation.targetCenter)) {
18192 return false;
18193 }
18194 }
18195 if (animation.sourceResolution !== animation.targetResolution) {
18196 return false;
18197 }
18198 if (animation.sourceRotation !== animation.targetRotation) {
18199 return false;
18200 }
18201 return true;
18202};
18203
18204goog.provide('ol.Kinetic');
18205
18206
18207/**
18208 * @classdesc
18209 * Implementation of inertial deceleration for map movement.
18210 *
18211 * @constructor
18212 * @param {number} decay Rate of decay (must be negative).
18213 * @param {number} minVelocity Minimum velocity (pixels/millisecond).
18214 * @param {number} delay Delay to consider to calculate the kinetic
18215 * initial values (milliseconds).
18216 * @struct
18217 * @api
18218 */
18219ol.Kinetic = function(decay, minVelocity, delay) {
18220
18221 /**
18222 * @private
18223 * @type {number}
18224 */
18225 this.decay_ = decay;
18226
18227 /**
18228 * @private
18229 * @type {number}
18230 */
18231 this.minVelocity_ = minVelocity;
18232
18233 /**
18234 * @private
18235 * @type {number}
18236 */
18237 this.delay_ = delay;
18238
18239 /**
18240 * @private
18241 * @type {Array.<number>}
18242 */
18243 this.points_ = [];
18244
18245 /**
18246 * @private
18247 * @type {number}
18248 */
18249 this.angle_ = 0;
18250
18251 /**
18252 * @private
18253 * @type {number}
18254 */
18255 this.initialVelocity_ = 0;
18256};
18257
18258
18259/**
18260 * FIXME empty description for jsdoc
18261 */
18262ol.Kinetic.prototype.begin = function() {
18263 this.points_.length = 0;
18264 this.angle_ = 0;
18265 this.initialVelocity_ = 0;
18266};
18267
18268
18269/**
18270 * @param {number} x X.
18271 * @param {number} y Y.
18272 */
18273ol.Kinetic.prototype.update = function(x, y) {
18274 this.points_.push(x, y, Date.now());
18275};
18276
18277
18278/**
18279 * @return {boolean} Whether we should do kinetic animation.
18280 */
18281ol.Kinetic.prototype.end = function() {
18282 if (this.points_.length < 6) {
18283 // at least 2 points are required (i.e. there must be at least 6 elements
18284 // in the array)
18285 return false;
18286 }
18287 var delay = Date.now() - this.delay_;
18288 var lastIndex = this.points_.length - 3;
18289 if (this.points_[lastIndex + 2] < delay) {
18290 // the last tracked point is too old, which means that the user stopped
18291 // panning before releasing the map
18292 return false;
18293 }
18294
18295 // get the first point which still falls into the delay time
18296 var firstIndex = lastIndex - 3;
18297 while (firstIndex > 0 && this.points_[firstIndex + 2] > delay) {
18298 firstIndex -= 3;
18299 }
18300
18301 var duration = this.points_[lastIndex + 2] - this.points_[firstIndex + 2];
18302 // we don't want a duration of 0 (divide by zero)
18303 // we also make sure the user panned for a duration of at least one frame
18304 // (1/60s) to compute sane displacement values
18305 if (duration < 1000 / 60) {
18306 return false;
18307 }
18308
18309 var dx = this.points_[lastIndex] - this.points_[firstIndex];
18310 var dy = this.points_[lastIndex + 1] - this.points_[firstIndex + 1];
18311 this.angle_ = Math.atan2(dy, dx);
18312 this.initialVelocity_ = Math.sqrt(dx * dx + dy * dy) / duration;
18313 return this.initialVelocity_ > this.minVelocity_;
18314};
18315
18316
18317/**
18318 * @return {number} Total distance travelled (pixels).
18319 */
18320ol.Kinetic.prototype.getDistance = function() {
18321 return (this.minVelocity_ - this.initialVelocity_) / this.decay_;
18322};
18323
18324
18325/**
18326 * @return {number} Angle of the kinetic panning animation (radians).
18327 */
18328ol.Kinetic.prototype.getAngle = function() {
18329 return this.angle_;
18330};
18331
18332goog.provide('ol.interaction.Property');
18333
18334/**
18335 * @enum {string}
18336 */
18337ol.interaction.Property = {
18338 ACTIVE: 'active'
18339};
18340
18341// FIXME factor out key precondition (shift et. al)
18342
18343goog.provide('ol.interaction.Interaction');
18344
18345goog.require('ol');
18346goog.require('ol.Object');
18347goog.require('ol.easing');
18348goog.require('ol.interaction.Property');
18349
18350
18351/**
18352 * @classdesc
18353 * Abstract base class; normally only used for creating subclasses and not
18354 * instantiated in apps.
18355 * User actions that change the state of the map. Some are similar to controls,
18356 * but are not associated with a DOM element.
18357 * For example, {@link ol.interaction.KeyboardZoom} is functionally the same as
18358 * {@link ol.control.Zoom}, but triggered by a keyboard event not a button
18359 * element event.
18360 * Although interactions do not have a DOM element, some of them do render
18361 * vectors and so are visible on the screen.
18362 *
18363 * @constructor
18364 * @param {olx.interaction.InteractionOptions} options Options.
18365 * @extends {ol.Object}
18366 * @api
18367 */
18368ol.interaction.Interaction = function(options) {
18369
18370 ol.Object.call(this);
18371
18372 /**
18373 * @private
18374 * @type {ol.Map}
18375 */
18376 this.map_ = null;
18377
18378 this.setActive(true);
18379
18380 /**
18381 * @type {function(ol.MapBrowserEvent):boolean}
18382 */
18383 this.handleEvent = options.handleEvent;
18384
18385};
18386ol.inherits(ol.interaction.Interaction, ol.Object);
18387
18388
18389/**
18390 * Return whether the interaction is currently active.
18391 * @return {boolean} `true` if the interaction is active, `false` otherwise.
18392 * @observable
18393 * @api
18394 */
18395ol.interaction.Interaction.prototype.getActive = function() {
18396 return /** @type {boolean} */ (
18397 this.get(ol.interaction.Property.ACTIVE));
18398};
18399
18400
18401/**
18402 * Get the map associated with this interaction.
18403 * @return {ol.Map} Map.
18404 * @api
18405 */
18406ol.interaction.Interaction.prototype.getMap = function() {
18407 return this.map_;
18408};
18409
18410
18411/**
18412 * Activate or deactivate the interaction.
18413 * @param {boolean} active Active.
18414 * @observable
18415 * @api
18416 */
18417ol.interaction.Interaction.prototype.setActive = function(active) {
18418 this.set(ol.interaction.Property.ACTIVE, active);
18419};
18420
18421
18422/**
18423 * Remove the interaction from its current map and attach it to the new map.
18424 * Subclasses may set up event handlers to get notified about changes to
18425 * the map here.
18426 * @param {ol.Map} map Map.
18427 */
18428ol.interaction.Interaction.prototype.setMap = function(map) {
18429 this.map_ = map;
18430};
18431
18432
18433/**
18434 * @param {ol.View} view View.
18435 * @param {ol.Coordinate} delta Delta.
18436 * @param {number=} opt_duration Duration.
18437 */
18438ol.interaction.Interaction.pan = function(view, delta, opt_duration) {
18439 var currentCenter = view.getCenter();
18440 if (currentCenter) {
18441 var center = view.constrainCenter(
18442 [currentCenter[0] + delta[0], currentCenter[1] + delta[1]]);
18443 if (opt_duration) {
18444 view.animate({
18445 duration: opt_duration,
18446 easing: ol.easing.linear,
18447 center: center
18448 });
18449 } else {
18450 view.setCenter(center);
18451 }
18452 }
18453};
18454
18455
18456/**
18457 * @param {ol.View} view View.
18458 * @param {number|undefined} rotation Rotation.
18459 * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
18460 * @param {number=} opt_duration Duration.
18461 */
18462ol.interaction.Interaction.rotate = function(view, rotation, opt_anchor, opt_duration) {
18463 rotation = view.constrainRotation(rotation, 0);
18464 ol.interaction.Interaction.rotateWithoutConstraints(
18465 view, rotation, opt_anchor, opt_duration);
18466};
18467
18468
18469/**
18470 * @param {ol.View} view View.
18471 * @param {number|undefined} rotation Rotation.
18472 * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
18473 * @param {number=} opt_duration Duration.
18474 */
18475ol.interaction.Interaction.rotateWithoutConstraints = function(view, rotation, opt_anchor, opt_duration) {
18476 if (rotation !== undefined) {
18477 var currentRotation = view.getRotation();
18478 var currentCenter = view.getCenter();
18479 if (currentRotation !== undefined && currentCenter && opt_duration > 0) {
18480 view.animate({
18481 rotation: rotation,
18482 anchor: opt_anchor,
18483 duration: opt_duration,
18484 easing: ol.easing.easeOut
18485 });
18486 } else {
18487 view.rotate(rotation, opt_anchor);
18488 }
18489 }
18490};
18491
18492
18493/**
18494 * @param {ol.View} view View.
18495 * @param {number|undefined} resolution Resolution to go to.
18496 * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
18497 * @param {number=} opt_duration Duration.
18498 * @param {number=} opt_direction Zooming direction; > 0 indicates
18499 * zooming out, in which case the constraints system will select
18500 * the largest nearest resolution; < 0 indicates zooming in, in
18501 * which case the constraints system will select the smallest
18502 * nearest resolution; == 0 indicates that the zooming direction
18503 * is unknown/not relevant, in which case the constraints system
18504 * will select the nearest resolution. If not defined 0 is
18505 * assumed.
18506 */
18507ol.interaction.Interaction.zoom = function(view, resolution, opt_anchor, opt_duration, opt_direction) {
18508 resolution = view.constrainResolution(resolution, 0, opt_direction);
18509 ol.interaction.Interaction.zoomWithoutConstraints(
18510 view, resolution, opt_anchor, opt_duration);
18511};
18512
18513
18514/**
18515 * @param {ol.View} view View.
18516 * @param {number} delta Delta from previous zoom level.
18517 * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
18518 * @param {number=} opt_duration Duration.
18519 */
18520ol.interaction.Interaction.zoomByDelta = function(view, delta, opt_anchor, opt_duration) {
18521 var currentResolution = view.getResolution();
18522 var resolution = view.constrainResolution(currentResolution, delta, 0);
18523
18524 // If we have a constraint on center, we need to change the anchor so that the
18525 // new center is within the extent. We first calculate the new center, apply
18526 // the constraint to it, and then calculate back the anchor
18527 if (opt_anchor && resolution !== undefined && resolution !== currentResolution) {
18528 var currentCenter = view.getCenter();
18529 var center = view.calculateCenterZoom(resolution, opt_anchor);
18530 center = view.constrainCenter(center);
18531
18532 opt_anchor = [
18533 (resolution * currentCenter[0] - currentResolution * center[0]) /
18534 (resolution - currentResolution),
18535 (resolution * currentCenter[1] - currentResolution * center[1]) /
18536 (resolution - currentResolution)
18537 ];
18538 }
18539
18540 ol.interaction.Interaction.zoomWithoutConstraints(
18541 view, resolution, opt_anchor, opt_duration);
18542};
18543
18544
18545/**
18546 * @param {ol.View} view View.
18547 * @param {number|undefined} resolution Resolution to go to.
18548 * @param {ol.Coordinate=} opt_anchor Anchor coordinate.
18549 * @param {number=} opt_duration Duration.
18550 */
18551ol.interaction.Interaction.zoomWithoutConstraints = function(view, resolution, opt_anchor, opt_duration) {
18552 if (resolution) {
18553 var currentResolution = view.getResolution();
18554 var currentCenter = view.getCenter();
18555 if (currentResolution !== undefined && currentCenter &&
18556 resolution !== currentResolution && opt_duration) {
18557 view.animate({
18558 resolution: resolution,
18559 anchor: opt_anchor,
18560 duration: opt_duration,
18561 easing: ol.easing.easeOut
18562 });
18563 } else {
18564 if (opt_anchor) {
18565 var center = view.calculateCenterZoom(resolution, opt_anchor);
18566 view.setCenter(center);
18567 }
18568 view.setResolution(resolution);
18569 }
18570 }
18571};
18572
18573goog.provide('ol.interaction.DoubleClickZoom');
18574
18575goog.require('ol');
18576goog.require('ol.MapBrowserEventType');
18577goog.require('ol.interaction.Interaction');
18578
18579
18580/**
18581 * @classdesc
18582 * Allows the user to zoom by double-clicking on the map.
18583 *
18584 * @constructor
18585 * @extends {ol.interaction.Interaction}
18586 * @param {olx.interaction.DoubleClickZoomOptions=} opt_options Options.
18587 * @api
18588 */
18589ol.interaction.DoubleClickZoom = function(opt_options) {
18590
18591 var options = opt_options ? opt_options : {};
18592
18593 /**
18594 * @private
18595 * @type {number}
18596 */
18597 this.delta_ = options.delta ? options.delta : 1;
18598
18599 ol.interaction.Interaction.call(this, {
18600 handleEvent: ol.interaction.DoubleClickZoom.handleEvent
18601 });
18602
18603 /**
18604 * @private
18605 * @type {number}
18606 */
18607 this.duration_ = options.duration !== undefined ? options.duration : 250;
18608
18609};
18610ol.inherits(ol.interaction.DoubleClickZoom, ol.interaction.Interaction);
18611
18612
18613/**
18614 * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a
18615 * doubleclick) and eventually zooms the map.
18616 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18617 * @return {boolean} `false` to stop event propagation.
18618 * @this {ol.interaction.DoubleClickZoom}
18619 * @api
18620 */
18621ol.interaction.DoubleClickZoom.handleEvent = function(mapBrowserEvent) {
18622 var stopEvent = false;
18623 var browserEvent = mapBrowserEvent.originalEvent;
18624 if (mapBrowserEvent.type == ol.MapBrowserEventType.DBLCLICK) {
18625 var map = mapBrowserEvent.map;
18626 var anchor = mapBrowserEvent.coordinate;
18627 var delta = browserEvent.shiftKey ? -this.delta_ : this.delta_;
18628 var view = map.getView();
18629 ol.interaction.Interaction.zoomByDelta(
18630 view, delta, anchor, this.duration_);
18631 mapBrowserEvent.preventDefault();
18632 stopEvent = true;
18633 }
18634 return !stopEvent;
18635};
18636
18637goog.provide('ol.events.condition');
18638
18639goog.require('ol.MapBrowserEventType');
18640goog.require('ol.asserts');
18641goog.require('ol.functions');
18642goog.require('ol.has');
18643
18644
18645/**
18646 * Return `true` if only the alt-key is pressed, `false` otherwise (e.g. when
18647 * additionally the shift-key is pressed).
18648 *
18649 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18650 * @return {boolean} True if only the alt key is pressed.
18651 * @api
18652 */
18653ol.events.condition.altKeyOnly = function(mapBrowserEvent) {
18654 var originalEvent = mapBrowserEvent.originalEvent;
18655 return (
18656 originalEvent.altKey &&
18657 !(originalEvent.metaKey || originalEvent.ctrlKey) &&
18658 !originalEvent.shiftKey);
18659};
18660
18661
18662/**
18663 * Return `true` if only the alt-key and shift-key is pressed, `false` otherwise
18664 * (e.g. when additionally the platform-modifier-key is pressed).
18665 *
18666 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18667 * @return {boolean} True if only the alt and shift keys are pressed.
18668 * @api
18669 */
18670ol.events.condition.altShiftKeysOnly = function(mapBrowserEvent) {
18671 var originalEvent = mapBrowserEvent.originalEvent;
18672 return (
18673 originalEvent.altKey &&
18674 !(originalEvent.metaKey || originalEvent.ctrlKey) &&
18675 originalEvent.shiftKey);
18676};
18677
18678
18679/**
18680 * Return always true.
18681 *
18682 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18683 * @return {boolean} True.
18684 * @function
18685 * @api
18686 */
18687ol.events.condition.always = ol.functions.TRUE;
18688
18689
18690/**
18691 * Return `true` if the event is a `click` event, `false` otherwise.
18692 *
18693 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18694 * @return {boolean} True if the event is a map `click` event.
18695 * @api
18696 */
18697ol.events.condition.click = function(mapBrowserEvent) {
18698 return mapBrowserEvent.type == ol.MapBrowserEventType.CLICK;
18699};
18700
18701
18702/**
18703 * Return `true` if the event has an "action"-producing mouse button.
18704 *
18705 * By definition, this includes left-click on windows/linux, and left-click
18706 * without the ctrl key on Macs.
18707 *
18708 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18709 * @return {boolean} The result.
18710 */
18711ol.events.condition.mouseActionButton = function(mapBrowserEvent) {
18712 var originalEvent = mapBrowserEvent.originalEvent;
18713 return originalEvent.button == 0 &&
18714 !(ol.has.WEBKIT && ol.has.MAC && originalEvent.ctrlKey);
18715};
18716
18717
18718/**
18719 * Return always false.
18720 *
18721 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18722 * @return {boolean} False.
18723 * @function
18724 * @api
18725 */
18726ol.events.condition.never = ol.functions.FALSE;
18727
18728
18729/**
18730 * Return `true` if the browser event is a `pointermove` event, `false`
18731 * otherwise.
18732 *
18733 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18734 * @return {boolean} True if the browser event is a `pointermove` event.
18735 * @api
18736 */
18737ol.events.condition.pointerMove = function(mapBrowserEvent) {
18738 return mapBrowserEvent.type == 'pointermove';
18739};
18740
18741
18742/**
18743 * Return `true` if the event is a map `singleclick` event, `false` otherwise.
18744 *
18745 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18746 * @return {boolean} True if the event is a map `singleclick` event.
18747 * @api
18748 */
18749ol.events.condition.singleClick = function(mapBrowserEvent) {
18750 return mapBrowserEvent.type == ol.MapBrowserEventType.SINGLECLICK;
18751};
18752
18753
18754/**
18755 * Return `true` if the event is a map `dblclick` event, `false` otherwise.
18756 *
18757 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18758 * @return {boolean} True if the event is a map `dblclick` event.
18759 * @api
18760 */
18761ol.events.condition.doubleClick = function(mapBrowserEvent) {
18762 return mapBrowserEvent.type == ol.MapBrowserEventType.DBLCLICK;
18763};
18764
18765
18766/**
18767 * Return `true` if no modifier key (alt-, shift- or platform-modifier-key) is
18768 * pressed.
18769 *
18770 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18771 * @return {boolean} True only if there no modifier keys are pressed.
18772 * @api
18773 */
18774ol.events.condition.noModifierKeys = function(mapBrowserEvent) {
18775 var originalEvent = mapBrowserEvent.originalEvent;
18776 return (
18777 !originalEvent.altKey &&
18778 !(originalEvent.metaKey || originalEvent.ctrlKey) &&
18779 !originalEvent.shiftKey);
18780};
18781
18782
18783/**
18784 * Return `true` if only the platform-modifier-key (the meta-key on Mac,
18785 * ctrl-key otherwise) is pressed, `false` otherwise (e.g. when additionally
18786 * the shift-key is pressed).
18787 *
18788 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18789 * @return {boolean} True if only the platform modifier key is pressed.
18790 * @api
18791 */
18792ol.events.condition.platformModifierKeyOnly = function(mapBrowserEvent) {
18793 var originalEvent = mapBrowserEvent.originalEvent;
18794 return (
18795 !originalEvent.altKey &&
18796 (ol.has.MAC ? originalEvent.metaKey : originalEvent.ctrlKey) &&
18797 !originalEvent.shiftKey);
18798};
18799
18800
18801/**
18802 * Return `true` if only the shift-key is pressed, `false` otherwise (e.g. when
18803 * additionally the alt-key is pressed).
18804 *
18805 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18806 * @return {boolean} True if only the shift key is pressed.
18807 * @api
18808 */
18809ol.events.condition.shiftKeyOnly = function(mapBrowserEvent) {
18810 var originalEvent = mapBrowserEvent.originalEvent;
18811 return (
18812 !originalEvent.altKey &&
18813 !(originalEvent.metaKey || originalEvent.ctrlKey) &&
18814 originalEvent.shiftKey);
18815};
18816
18817
18818/**
18819 * Return `true` if the target element is not editable, i.e. not a `<input>`-,
18820 * `<select>`- or `<textarea>`-element, `false` otherwise.
18821 *
18822 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18823 * @return {boolean} True only if the target element is not editable.
18824 * @api
18825 */
18826ol.events.condition.targetNotEditable = function(mapBrowserEvent) {
18827 var target = mapBrowserEvent.originalEvent.target;
18828 var tagName = target.tagName;
18829 return (
18830 tagName !== 'INPUT' &&
18831 tagName !== 'SELECT' &&
18832 tagName !== 'TEXTAREA');
18833};
18834
18835
18836/**
18837 * Return `true` if the event originates from a mouse device.
18838 *
18839 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18840 * @return {boolean} True if the event originates from a mouse device.
18841 * @api
18842 */
18843ol.events.condition.mouseOnly = function(mapBrowserEvent) {
18844 ol.asserts.assert(mapBrowserEvent.pointerEvent, 56); // mapBrowserEvent must originate from a pointer event
18845 // see http://www.w3.org/TR/pointerevents/#widl-PointerEvent-pointerType
18846 return /** @type {ol.MapBrowserEvent} */ (mapBrowserEvent).pointerEvent.pointerType == 'mouse';
18847};
18848
18849
18850/**
18851 * Return `true` if the event originates from a primary pointer in
18852 * contact with the surface or if the left mouse button is pressed.
18853 * @see http://www.w3.org/TR/pointerevents/#button-states
18854 *
18855 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
18856 * @return {boolean} True if the event originates from a primary pointer.
18857 * @api
18858 */
18859ol.events.condition.primaryAction = function(mapBrowserEvent) {
18860 var pointerEvent = mapBrowserEvent.pointerEvent;
18861 return pointerEvent.isPrimary && pointerEvent.button === 0;
18862};
18863
18864goog.provide('ol.interaction.Pointer');
18865
18866goog.require('ol');
18867goog.require('ol.functions');
18868goog.require('ol.MapBrowserEventType');
18869goog.require('ol.MapBrowserPointerEvent');
18870goog.require('ol.interaction.Interaction');
18871goog.require('ol.obj');
18872
18873
18874/**
18875 * @classdesc
18876 * Base class that calls user-defined functions on `down`, `move` and `up`
18877 * events. This class also manages "drag sequences".
18878 *
18879 * When the `handleDownEvent` user function returns `true` a drag sequence is
18880 * started. During a drag sequence the `handleDragEvent` user function is
18881 * called on `move` events. The drag sequence ends when the `handleUpEvent`
18882 * user function is called and returns `false`.
18883 *
18884 * @constructor
18885 * @param {olx.interaction.PointerOptions=} opt_options Options.
18886 * @extends {ol.interaction.Interaction}
18887 * @api
18888 */
18889ol.interaction.Pointer = function(opt_options) {
18890
18891 var options = opt_options ? opt_options : {};
18892
18893 var handleEvent = options.handleEvent ?
18894 options.handleEvent : ol.interaction.Pointer.handleEvent;
18895
18896 ol.interaction.Interaction.call(this, {
18897 handleEvent: handleEvent
18898 });
18899
18900 /**
18901 * @type {function(ol.MapBrowserPointerEvent):boolean}
18902 * @private
18903 */
18904 this.handleDownEvent_ = options.handleDownEvent ?
18905 options.handleDownEvent : ol.interaction.Pointer.handleDownEvent;
18906
18907 /**
18908 * @type {function(ol.MapBrowserPointerEvent)}
18909 * @private
18910 */
18911 this.handleDragEvent_ = options.handleDragEvent ?
18912 options.handleDragEvent : ol.interaction.Pointer.handleDragEvent;
18913
18914 /**
18915 * @type {function(ol.MapBrowserPointerEvent)}
18916 * @private
18917 */
18918 this.handleMoveEvent_ = options.handleMoveEvent ?
18919 options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent;
18920
18921 /**
18922 * @type {function(ol.MapBrowserPointerEvent):boolean}
18923 * @private
18924 */
18925 this.handleUpEvent_ = options.handleUpEvent ?
18926 options.handleUpEvent : ol.interaction.Pointer.handleUpEvent;
18927
18928 /**
18929 * @type {boolean}
18930 * @protected
18931 */
18932 this.handlingDownUpSequence = false;
18933
18934 /**
18935 * @type {Object.<number, ol.pointer.PointerEvent>}
18936 * @private
18937 */
18938 this.trackedPointers_ = {};
18939
18940 /**
18941 * @type {Array.<ol.pointer.PointerEvent>}
18942 * @protected
18943 */
18944 this.targetPointers = [];
18945
18946};
18947ol.inherits(ol.interaction.Pointer, ol.interaction.Interaction);
18948
18949
18950/**
18951 * @param {Array.<ol.pointer.PointerEvent>} pointerEvents List of events.
18952 * @return {ol.Pixel} Centroid pixel.
18953 */
18954ol.interaction.Pointer.centroid = function(pointerEvents) {
18955 var length = pointerEvents.length;
18956 var clientX = 0;
18957 var clientY = 0;
18958 for (var i = 0; i < length; i++) {
18959 clientX += pointerEvents[i].clientX;
18960 clientY += pointerEvents[i].clientY;
18961 }
18962 return [clientX / length, clientY / length];
18963};
18964
18965
18966/**
18967 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
18968 * @return {boolean} Whether the event is a pointerdown, pointerdrag
18969 * or pointerup event.
18970 * @private
18971 */
18972ol.interaction.Pointer.prototype.isPointerDraggingEvent_ = function(mapBrowserEvent) {
18973 var type = mapBrowserEvent.type;
18974 return (
18975 type === ol.MapBrowserEventType.POINTERDOWN ||
18976 type === ol.MapBrowserEventType.POINTERDRAG ||
18977 type === ol.MapBrowserEventType.POINTERUP);
18978};
18979
18980
18981/**
18982 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
18983 * @private
18984 */
18985ol.interaction.Pointer.prototype.updateTrackedPointers_ = function(mapBrowserEvent) {
18986 if (this.isPointerDraggingEvent_(mapBrowserEvent)) {
18987 var event = mapBrowserEvent.pointerEvent;
18988
18989 if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
18990 delete this.trackedPointers_[event.pointerId];
18991 } else if (mapBrowserEvent.type ==
18992 ol.MapBrowserEventType.POINTERDOWN) {
18993 this.trackedPointers_[event.pointerId] = event;
18994 } else if (event.pointerId in this.trackedPointers_) {
18995 // update only when there was a pointerdown event for this pointer
18996 this.trackedPointers_[event.pointerId] = event;
18997 }
18998 this.targetPointers = ol.obj.getValues(this.trackedPointers_);
18999 }
19000};
19001
19002
19003/**
19004 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19005 * @this {ol.interaction.Pointer}
19006 */
19007ol.interaction.Pointer.handleDragEvent = ol.nullFunction;
19008
19009
19010/**
19011 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19012 * @return {boolean} Capture dragging.
19013 * @this {ol.interaction.Pointer}
19014 */
19015ol.interaction.Pointer.handleUpEvent = ol.functions.FALSE;
19016
19017
19018/**
19019 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19020 * @return {boolean} Capture dragging.
19021 * @this {ol.interaction.Pointer}
19022 */
19023ol.interaction.Pointer.handleDownEvent = ol.functions.FALSE;
19024
19025
19026/**
19027 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19028 * @this {ol.interaction.Pointer}
19029 */
19030ol.interaction.Pointer.handleMoveEvent = ol.nullFunction;
19031
19032
19033/**
19034 * Handles the {@link ol.MapBrowserEvent map browser event} and may call into
19035 * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are
19036 * detected.
19037 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
19038 * @return {boolean} `false` to stop event propagation.
19039 * @this {ol.interaction.Pointer}
19040 * @api
19041 */
19042ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) {
19043 if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
19044 return true;
19045 }
19046
19047 var stopEvent = false;
19048 this.updateTrackedPointers_(mapBrowserEvent);
19049 if (this.handlingDownUpSequence) {
19050 if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDRAG) {
19051 this.handleDragEvent_(mapBrowserEvent);
19052 } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERUP) {
19053 var handledUp = this.handleUpEvent_(mapBrowserEvent);
19054 this.handlingDownUpSequence = handledUp && this.targetPointers.length > 0;
19055 }
19056 } else {
19057 if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERDOWN) {
19058 var handled = this.handleDownEvent_(mapBrowserEvent);
19059 this.handlingDownUpSequence = handled;
19060 stopEvent = this.shouldStopEvent(handled);
19061 } else if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE) {
19062 this.handleMoveEvent_(mapBrowserEvent);
19063 }
19064 }
19065 return !stopEvent;
19066};
19067
19068
19069/**
19070 * This method is used to determine if "down" events should be propagated to
19071 * other interactions or should be stopped.
19072 *
19073 * The method receives the return code of the "handleDownEvent" function.
19074 *
19075 * By default this function is the "identity" function. It's overidden in
19076 * child classes.
19077 *
19078 * @param {boolean} handled Was the event handled by the interaction?
19079 * @return {boolean} Should the event be stopped?
19080 * @protected
19081 */
19082ol.interaction.Pointer.prototype.shouldStopEvent = function(handled) {
19083 return handled;
19084};
19085
19086goog.provide('ol.interaction.DragPan');
19087
19088goog.require('ol');
19089goog.require('ol.ViewHint');
19090goog.require('ol.coordinate');
19091goog.require('ol.easing');
19092goog.require('ol.events.condition');
19093goog.require('ol.functions');
19094goog.require('ol.interaction.Pointer');
19095
19096
19097/**
19098 * @classdesc
19099 * Allows the user to pan the map by dragging the map.
19100 *
19101 * @constructor
19102 * @extends {ol.interaction.Pointer}
19103 * @param {olx.interaction.DragPanOptions=} opt_options Options.
19104 * @api
19105 */
19106ol.interaction.DragPan = function(opt_options) {
19107
19108 ol.interaction.Pointer.call(this, {
19109 handleDownEvent: ol.interaction.DragPan.handleDownEvent_,
19110 handleDragEvent: ol.interaction.DragPan.handleDragEvent_,
19111 handleUpEvent: ol.interaction.DragPan.handleUpEvent_
19112 });
19113
19114 var options = opt_options ? opt_options : {};
19115
19116 /**
19117 * @private
19118 * @type {ol.Kinetic|undefined}
19119 */
19120 this.kinetic_ = options.kinetic;
19121
19122 /**
19123 * @type {ol.Pixel}
19124 */
19125 this.lastCentroid = null;
19126
19127 /**
19128 * @type {number}
19129 */
19130 this.lastPointersCount_;
19131
19132 /**
19133 * @private
19134 * @type {ol.EventsConditionType}
19135 */
19136 this.condition_ = options.condition ?
19137 options.condition : ol.events.condition.noModifierKeys;
19138
19139 /**
19140 * @private
19141 * @type {boolean}
19142 */
19143 this.noKinetic_ = false;
19144
19145};
19146ol.inherits(ol.interaction.DragPan, ol.interaction.Pointer);
19147
19148
19149/**
19150 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19151 * @this {ol.interaction.DragPan}
19152 * @private
19153 */
19154ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) {
19155 var targetPointers = this.targetPointers;
19156 var centroid =
19157 ol.interaction.Pointer.centroid(targetPointers);
19158 if (targetPointers.length == this.lastPointersCount_) {
19159 if (this.kinetic_) {
19160 this.kinetic_.update(centroid[0], centroid[1]);
19161 }
19162 if (this.lastCentroid) {
19163 var deltaX = this.lastCentroid[0] - centroid[0];
19164 var deltaY = centroid[1] - this.lastCentroid[1];
19165 var map = mapBrowserEvent.map;
19166 var view = map.getView();
19167 var viewState = view.getState();
19168 var center = [deltaX, deltaY];
19169 ol.coordinate.scale(center, viewState.resolution);
19170 ol.coordinate.rotate(center, viewState.rotation);
19171 ol.coordinate.add(center, viewState.center);
19172 center = view.constrainCenter(center);
19173 view.setCenter(center);
19174 }
19175 } else if (this.kinetic_) {
19176 // reset so we don't overestimate the kinetic energy after
19177 // after one finger down, tiny drag, second finger down
19178 this.kinetic_.begin();
19179 }
19180 this.lastCentroid = centroid;
19181 this.lastPointersCount_ = targetPointers.length;
19182};
19183
19184
19185/**
19186 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19187 * @return {boolean} Stop drag sequence?
19188 * @this {ol.interaction.DragPan}
19189 * @private
19190 */
19191ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) {
19192 var map = mapBrowserEvent.map;
19193 var view = map.getView();
19194 if (this.targetPointers.length === 0) {
19195 if (!this.noKinetic_ && this.kinetic_ && this.kinetic_.end()) {
19196 var distance = this.kinetic_.getDistance();
19197 var angle = this.kinetic_.getAngle();
19198 var center = /** @type {!ol.Coordinate} */ (view.getCenter());
19199 var centerpx = map.getPixelFromCoordinate(center);
19200 var dest = map.getCoordinateFromPixel([
19201 centerpx[0] - distance * Math.cos(angle),
19202 centerpx[1] - distance * Math.sin(angle)
19203 ]);
19204 view.animate({
19205 center: view.constrainCenter(dest),
19206 duration: 500,
19207 easing: ol.easing.easeOut
19208 });
19209 }
19210 view.setHint(ol.ViewHint.INTERACTING, -1);
19211 return false;
19212 } else {
19213 if (this.kinetic_) {
19214 // reset so we don't overestimate the kinetic energy after
19215 // after one finger up, tiny drag, second finger up
19216 this.kinetic_.begin();
19217 }
19218 this.lastCentroid = null;
19219 return true;
19220 }
19221};
19222
19223
19224/**
19225 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19226 * @return {boolean} Start drag sequence?
19227 * @this {ol.interaction.DragPan}
19228 * @private
19229 */
19230ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) {
19231 if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) {
19232 var map = mapBrowserEvent.map;
19233 var view = map.getView();
19234 this.lastCentroid = null;
19235 if (!this.handlingDownUpSequence) {
19236 view.setHint(ol.ViewHint.INTERACTING, 1);
19237 }
19238 // stop any current animation
19239 if (view.getHints()[ol.ViewHint.ANIMATING]) {
19240 view.setCenter(mapBrowserEvent.frameState.viewState.center);
19241 }
19242 if (this.kinetic_) {
19243 this.kinetic_.begin();
19244 }
19245 // No kinetic as soon as more than one pointer on the screen is
19246 // detected. This is to prevent nasty pans after pinch.
19247 this.noKinetic_ = this.targetPointers.length > 1;
19248 return true;
19249 } else {
19250 return false;
19251 }
19252};
19253
19254
19255/**
19256 * @inheritDoc
19257 */
19258ol.interaction.DragPan.prototype.shouldStopEvent = ol.functions.FALSE;
19259
19260goog.provide('ol.interaction.DragRotate');
19261
19262goog.require('ol');
19263goog.require('ol.RotationConstraint');
19264goog.require('ol.ViewHint');
19265goog.require('ol.events.condition');
19266goog.require('ol.functions');
19267goog.require('ol.interaction.Interaction');
19268goog.require('ol.interaction.Pointer');
19269
19270
19271/**
19272 * @classdesc
19273 * Allows the user to rotate the map by clicking and dragging on the map,
19274 * normally combined with an {@link ol.events.condition} that limits
19275 * it to when the alt and shift keys are held down.
19276 *
19277 * This interaction is only supported for mouse devices.
19278 *
19279 * @constructor
19280 * @extends {ol.interaction.Pointer}
19281 * @param {olx.interaction.DragRotateOptions=} opt_options Options.
19282 * @api
19283 */
19284ol.interaction.DragRotate = function(opt_options) {
19285
19286 var options = opt_options ? opt_options : {};
19287
19288 ol.interaction.Pointer.call(this, {
19289 handleDownEvent: ol.interaction.DragRotate.handleDownEvent_,
19290 handleDragEvent: ol.interaction.DragRotate.handleDragEvent_,
19291 handleUpEvent: ol.interaction.DragRotate.handleUpEvent_
19292 });
19293
19294 /**
19295 * @private
19296 * @type {ol.EventsConditionType}
19297 */
19298 this.condition_ = options.condition ?
19299 options.condition : ol.events.condition.altShiftKeysOnly;
19300
19301 /**
19302 * @private
19303 * @type {number|undefined}
19304 */
19305 this.lastAngle_ = undefined;
19306
19307 /**
19308 * @private
19309 * @type {number}
19310 */
19311 this.duration_ = options.duration !== undefined ? options.duration : 250;
19312};
19313ol.inherits(ol.interaction.DragRotate, ol.interaction.Pointer);
19314
19315
19316/**
19317 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19318 * @this {ol.interaction.DragRotate}
19319 * @private
19320 */
19321ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) {
19322 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19323 return;
19324 }
19325
19326 var map = mapBrowserEvent.map;
19327 var view = map.getView();
19328 if (view.getConstraints().rotation === ol.RotationConstraint.disable) {
19329 return;
19330 }
19331 var size = map.getSize();
19332 var offset = mapBrowserEvent.pixel;
19333 var theta =
19334 Math.atan2(size[1] / 2 - offset[1], offset[0] - size[0] / 2);
19335 if (this.lastAngle_ !== undefined) {
19336 var delta = theta - this.lastAngle_;
19337 var rotation = view.getRotation();
19338 ol.interaction.Interaction.rotateWithoutConstraints(
19339 view, rotation - delta);
19340 }
19341 this.lastAngle_ = theta;
19342};
19343
19344
19345/**
19346 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19347 * @return {boolean} Stop drag sequence?
19348 * @this {ol.interaction.DragRotate}
19349 * @private
19350 */
19351ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) {
19352 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19353 return true;
19354 }
19355
19356 var map = mapBrowserEvent.map;
19357 var view = map.getView();
19358 view.setHint(ol.ViewHint.INTERACTING, -1);
19359 var rotation = view.getRotation();
19360 ol.interaction.Interaction.rotate(view, rotation,
19361 undefined, this.duration_);
19362 return false;
19363};
19364
19365
19366/**
19367 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19368 * @return {boolean} Start drag sequence?
19369 * @this {ol.interaction.DragRotate}
19370 * @private
19371 */
19372ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) {
19373 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19374 return false;
19375 }
19376
19377 if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&
19378 this.condition_(mapBrowserEvent)) {
19379 var map = mapBrowserEvent.map;
19380 map.getView().setHint(ol.ViewHint.INTERACTING, 1);
19381 this.lastAngle_ = undefined;
19382 return true;
19383 } else {
19384 return false;
19385 }
19386};
19387
19388
19389/**
19390 * @inheritDoc
19391 */
19392ol.interaction.DragRotate.prototype.shouldStopEvent = ol.functions.FALSE;
19393
19394// FIXME add rotation
19395
19396goog.provide('ol.render.Box');
19397
19398goog.require('ol');
19399goog.require('ol.Disposable');
19400goog.require('ol.geom.Polygon');
19401
19402
19403/**
19404 * @constructor
19405 * @extends {ol.Disposable}
19406 * @param {string} className CSS class name.
19407 */
19408ol.render.Box = function(className) {
19409
19410 /**
19411 * @type {ol.geom.Polygon}
19412 * @private
19413 */
19414 this.geometry_ = null;
19415
19416 /**
19417 * @type {HTMLDivElement}
19418 * @private
19419 */
19420 this.element_ = /** @type {HTMLDivElement} */ (document.createElement('div'));
19421 this.element_.style.position = 'absolute';
19422 this.element_.className = 'ol-box ' + className;
19423
19424 /**
19425 * @private
19426 * @type {ol.Map}
19427 */
19428 this.map_ = null;
19429
19430 /**
19431 * @private
19432 * @type {ol.Pixel}
19433 */
19434 this.startPixel_ = null;
19435
19436 /**
19437 * @private
19438 * @type {ol.Pixel}
19439 */
19440 this.endPixel_ = null;
19441
19442};
19443ol.inherits(ol.render.Box, ol.Disposable);
19444
19445
19446/**
19447 * @inheritDoc
19448 */
19449ol.render.Box.prototype.disposeInternal = function() {
19450 this.setMap(null);
19451};
19452
19453
19454/**
19455 * @private
19456 */
19457ol.render.Box.prototype.render_ = function() {
19458 var startPixel = this.startPixel_;
19459 var endPixel = this.endPixel_;
19460 var px = 'px';
19461 var style = this.element_.style;
19462 style.left = Math.min(startPixel[0], endPixel[0]) + px;
19463 style.top = Math.min(startPixel[1], endPixel[1]) + px;
19464 style.width = Math.abs(endPixel[0] - startPixel[0]) + px;
19465 style.height = Math.abs(endPixel[1] - startPixel[1]) + px;
19466};
19467
19468
19469/**
19470 * @param {ol.Map} map Map.
19471 */
19472ol.render.Box.prototype.setMap = function(map) {
19473 if (this.map_) {
19474 this.map_.getOverlayContainer().removeChild(this.element_);
19475 var style = this.element_.style;
19476 style.left = style.top = style.width = style.height = 'inherit';
19477 }
19478 this.map_ = map;
19479 if (this.map_) {
19480 this.map_.getOverlayContainer().appendChild(this.element_);
19481 }
19482};
19483
19484
19485/**
19486 * @param {ol.Pixel} startPixel Start pixel.
19487 * @param {ol.Pixel} endPixel End pixel.
19488 */
19489ol.render.Box.prototype.setPixels = function(startPixel, endPixel) {
19490 this.startPixel_ = startPixel;
19491 this.endPixel_ = endPixel;
19492 this.createOrUpdateGeometry();
19493 this.render_();
19494};
19495
19496
19497/**
19498 * Creates or updates the cached geometry.
19499 */
19500ol.render.Box.prototype.createOrUpdateGeometry = function() {
19501 var startPixel = this.startPixel_;
19502 var endPixel = this.endPixel_;
19503 var pixels = [
19504 startPixel,
19505 [startPixel[0], endPixel[1]],
19506 endPixel,
19507 [endPixel[0], startPixel[1]]
19508 ];
19509 var coordinates = pixels.map(this.map_.getCoordinateFromPixel, this.map_);
19510 // close the polygon
19511 coordinates[4] = coordinates[0].slice();
19512 if (!this.geometry_) {
19513 this.geometry_ = new ol.geom.Polygon([coordinates]);
19514 } else {
19515 this.geometry_.setCoordinates([coordinates]);
19516 }
19517};
19518
19519
19520/**
19521 * @return {ol.geom.Polygon} Geometry.
19522 */
19523ol.render.Box.prototype.getGeometry = function() {
19524 return this.geometry_;
19525};
19526
19527// FIXME draw drag box
19528goog.provide('ol.interaction.DragBox');
19529
19530goog.require('ol.events.Event');
19531goog.require('ol');
19532goog.require('ol.events.condition');
19533goog.require('ol.interaction.Pointer');
19534goog.require('ol.render.Box');
19535
19536
19537/**
19538 * @classdesc
19539 * Allows the user to draw a vector box by clicking and dragging on the map,
19540 * normally combined with an {@link ol.events.condition} that limits
19541 * it to when the shift or other key is held down. This is used, for example,
19542 * for zooming to a specific area of the map
19543 * (see {@link ol.interaction.DragZoom} and
19544 * {@link ol.interaction.DragRotateAndZoom}).
19545 *
19546 * This interaction is only supported for mouse devices.
19547 *
19548 * @constructor
19549 * @extends {ol.interaction.Pointer}
19550 * @fires ol.interaction.DragBox.Event
19551 * @param {olx.interaction.DragBoxOptions=} opt_options Options.
19552 * @api
19553 */
19554ol.interaction.DragBox = function(opt_options) {
19555
19556 ol.interaction.Pointer.call(this, {
19557 handleDownEvent: ol.interaction.DragBox.handleDownEvent_,
19558 handleDragEvent: ol.interaction.DragBox.handleDragEvent_,
19559 handleUpEvent: ol.interaction.DragBox.handleUpEvent_
19560 });
19561
19562 var options = opt_options ? opt_options : {};
19563
19564 /**
19565 * @type {ol.render.Box}
19566 * @private
19567 */
19568 this.box_ = new ol.render.Box(options.className || 'ol-dragbox');
19569
19570 /**
19571 * @type {number}
19572 * @private
19573 */
19574 this.minArea_ = options.minArea !== undefined ? options.minArea : 64;
19575
19576 /**
19577 * @type {ol.Pixel}
19578 * @private
19579 */
19580 this.startPixel_ = null;
19581
19582 /**
19583 * @private
19584 * @type {ol.EventsConditionType}
19585 */
19586 this.condition_ = options.condition ?
19587 options.condition : ol.events.condition.always;
19588
19589 /**
19590 * @private
19591 * @type {ol.DragBoxEndConditionType}
19592 */
19593 this.boxEndCondition_ = options.boxEndCondition ?
19594 options.boxEndCondition : ol.interaction.DragBox.defaultBoxEndCondition;
19595};
19596ol.inherits(ol.interaction.DragBox, ol.interaction.Pointer);
19597
19598
19599/**
19600 * The default condition for determining whether the boxend event
19601 * should fire.
19602 * @param {ol.MapBrowserEvent} mapBrowserEvent The originating MapBrowserEvent
19603 * leading to the box end.
19604 * @param {ol.Pixel} startPixel The starting pixel of the box.
19605 * @param {ol.Pixel} endPixel The end pixel of the box.
19606 * @return {boolean} Whether or not the boxend condition should be fired.
19607 * @this {ol.interaction.DragBox}
19608 */
19609ol.interaction.DragBox.defaultBoxEndCondition = function(mapBrowserEvent, startPixel, endPixel) {
19610 var width = endPixel[0] - startPixel[0];
19611 var height = endPixel[1] - startPixel[1];
19612 return width * width + height * height >= this.minArea_;
19613};
19614
19615
19616/**
19617 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19618 * @this {ol.interaction.DragBox}
19619 * @private
19620 */
19621ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) {
19622 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19623 return;
19624 }
19625
19626 this.box_.setPixels(this.startPixel_, mapBrowserEvent.pixel);
19627
19628 this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType_.BOXDRAG,
19629 mapBrowserEvent.coordinate, mapBrowserEvent));
19630};
19631
19632
19633/**
19634 * Returns geometry of last drawn box.
19635 * @return {ol.geom.Polygon} Geometry.
19636 * @api
19637 */
19638ol.interaction.DragBox.prototype.getGeometry = function() {
19639 return this.box_.getGeometry();
19640};
19641
19642
19643/**
19644 * To be overridden by child classes.
19645 * FIXME: use constructor option instead of relying on overriding.
19646 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
19647 * @protected
19648 */
19649ol.interaction.DragBox.prototype.onBoxEnd = ol.nullFunction;
19650
19651
19652/**
19653 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19654 * @return {boolean} Stop drag sequence?
19655 * @this {ol.interaction.DragBox}
19656 * @private
19657 */
19658ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) {
19659 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19660 return true;
19661 }
19662
19663 this.box_.setMap(null);
19664
19665 if (this.boxEndCondition_(mapBrowserEvent,
19666 this.startPixel_, mapBrowserEvent.pixel)) {
19667 this.onBoxEnd(mapBrowserEvent);
19668 this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType_.BOXEND,
19669 mapBrowserEvent.coordinate, mapBrowserEvent));
19670 }
19671 return false;
19672};
19673
19674
19675/**
19676 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
19677 * @return {boolean} Start drag sequence?
19678 * @this {ol.interaction.DragBox}
19679 * @private
19680 */
19681ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) {
19682 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
19683 return false;
19684 }
19685
19686 if (ol.events.condition.mouseActionButton(mapBrowserEvent) &&
19687 this.condition_(mapBrowserEvent)) {
19688 this.startPixel_ = mapBrowserEvent.pixel;
19689 this.box_.setMap(mapBrowserEvent.map);
19690 this.box_.setPixels(this.startPixel_, this.startPixel_);
19691 this.dispatchEvent(new ol.interaction.DragBox.Event(ol.interaction.DragBox.EventType_.BOXSTART,
19692 mapBrowserEvent.coordinate, mapBrowserEvent));
19693 return true;
19694 } else {
19695 return false;
19696 }
19697};
19698
19699
19700/**
19701 * @enum {string}
19702 * @private
19703 */
19704ol.interaction.DragBox.EventType_ = {
19705 /**
19706 * Triggered upon drag box start.
19707 * @event ol.interaction.DragBox.Event#boxstart
19708 * @api
19709 */
19710 BOXSTART: 'boxstart',
19711
19712 /**
19713 * Triggered on drag when box is active.
19714 * @event ol.interaction.DragBox.Event#boxdrag
19715 * @api
19716 */
19717 BOXDRAG: 'boxdrag',
19718
19719 /**
19720 * Triggered upon drag box end.
19721 * @event ol.interaction.DragBox.Event#boxend
19722 * @api
19723 */
19724 BOXEND: 'boxend'
19725};
19726
19727
19728/**
19729 * @classdesc
19730 * Events emitted by {@link ol.interaction.DragBox} instances are instances of
19731 * this type.
19732 *
19733 * @param {string} type The event type.
19734 * @param {ol.Coordinate} coordinate The event coordinate.
19735 * @param {ol.MapBrowserEvent} mapBrowserEvent Originating event.
19736 * @extends {ol.events.Event}
19737 * @constructor
19738 * @implements {oli.DragBoxEvent}
19739 */
19740ol.interaction.DragBox.Event = function(type, coordinate, mapBrowserEvent) {
19741 ol.events.Event.call(this, type);
19742
19743 /**
19744 * The coordinate of the drag event.
19745 * @const
19746 * @type {ol.Coordinate}
19747 * @api
19748 */
19749 this.coordinate = coordinate;
19750
19751 /**
19752 * @const
19753 * @type {ol.MapBrowserEvent}
19754 * @api
19755 */
19756 this.mapBrowserEvent = mapBrowserEvent;
19757
19758};
19759ol.inherits(ol.interaction.DragBox.Event, ol.events.Event);
19760
19761goog.provide('ol.interaction.DragZoom');
19762
19763goog.require('ol');
19764goog.require('ol.easing');
19765goog.require('ol.events.condition');
19766goog.require('ol.extent');
19767goog.require('ol.interaction.DragBox');
19768
19769
19770/**
19771 * @classdesc
19772 * Allows the user to zoom the map by clicking and dragging on the map,
19773 * normally combined with an {@link ol.events.condition} that limits
19774 * it to when a key, shift by default, is held down.
19775 *
19776 * To change the style of the box, use CSS and the `.ol-dragzoom` selector, or
19777 * your custom one configured with `className`.
19778 *
19779 * @constructor
19780 * @extends {ol.interaction.DragBox}
19781 * @param {olx.interaction.DragZoomOptions=} opt_options Options.
19782 * @api
19783 */
19784ol.interaction.DragZoom = function(opt_options) {
19785 var options = opt_options ? opt_options : {};
19786
19787 var condition = options.condition ?
19788 options.condition : ol.events.condition.shiftKeyOnly;
19789
19790 /**
19791 * @private
19792 * @type {number}
19793 */
19794 this.duration_ = options.duration !== undefined ? options.duration : 200;
19795
19796 /**
19797 * @private
19798 * @type {boolean}
19799 */
19800 this.out_ = options.out !== undefined ? options.out : false;
19801
19802 ol.interaction.DragBox.call(this, {
19803 condition: condition,
19804 className: options.className || 'ol-dragzoom'
19805 });
19806
19807};
19808ol.inherits(ol.interaction.DragZoom, ol.interaction.DragBox);
19809
19810
19811/**
19812 * @inheritDoc
19813 */
19814ol.interaction.DragZoom.prototype.onBoxEnd = function() {
19815 var map = this.getMap();
19816
19817 var view = /** @type {!ol.View} */ (map.getView());
19818
19819 var size = /** @type {!ol.Size} */ (map.getSize());
19820
19821 var extent = this.getGeometry().getExtent();
19822
19823 if (this.out_) {
19824 var mapExtent = view.calculateExtent(size);
19825 var boxPixelExtent = ol.extent.createOrUpdateFromCoordinates([
19826 map.getPixelFromCoordinate(ol.extent.getBottomLeft(extent)),
19827 map.getPixelFromCoordinate(ol.extent.getTopRight(extent))]);
19828 var factor = view.getResolutionForExtent(boxPixelExtent, size);
19829
19830 ol.extent.scaleFromCenter(mapExtent, 1 / factor);
19831 extent = mapExtent;
19832 }
19833
19834 var resolution = view.constrainResolution(
19835 view.getResolutionForExtent(extent, size));
19836
19837 var center = ol.extent.getCenter(extent);
19838 center = view.constrainCenter(center);
19839
19840 view.animate({
19841 resolution: resolution,
19842 center: center,
19843 duration: this.duration_,
19844 easing: ol.easing.easeOut
19845 });
19846
19847};
19848
19849goog.provide('ol.events.KeyCode');
19850
19851/**
19852 * @enum {number}
19853 * @const
19854 */
19855ol.events.KeyCode = {
19856 LEFT: 37,
19857 UP: 38,
19858 RIGHT: 39,
19859 DOWN: 40
19860};
19861
19862goog.provide('ol.interaction.KeyboardPan');
19863
19864goog.require('ol');
19865goog.require('ol.coordinate');
19866goog.require('ol.events.EventType');
19867goog.require('ol.events.KeyCode');
19868goog.require('ol.events.condition');
19869goog.require('ol.interaction.Interaction');
19870
19871
19872/**
19873 * @classdesc
19874 * Allows the user to pan the map using keyboard arrows.
19875 * Note that, although this interaction is by default included in maps,
19876 * the keys can only be used when browser focus is on the element to which
19877 * the keyboard events are attached. By default, this is the map div,
19878 * though you can change this with the `keyboardEventTarget` in
19879 * {@link ol.Map}. `document` never loses focus but, for any other element,
19880 * focus will have to be on, and returned to, this element if the keys are to
19881 * function.
19882 * See also {@link ol.interaction.KeyboardZoom}.
19883 *
19884 * @constructor
19885 * @extends {ol.interaction.Interaction}
19886 * @param {olx.interaction.KeyboardPanOptions=} opt_options Options.
19887 * @api
19888 */
19889ol.interaction.KeyboardPan = function(opt_options) {
19890
19891 ol.interaction.Interaction.call(this, {
19892 handleEvent: ol.interaction.KeyboardPan.handleEvent
19893 });
19894
19895 var options = opt_options || {};
19896
19897 /**
19898 * @private
19899 * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
19900 * @return {boolean} Combined condition result.
19901 */
19902 this.defaultCondition_ = function(mapBrowserEvent) {
19903 return ol.events.condition.noModifierKeys(mapBrowserEvent) &&
19904 ol.events.condition.targetNotEditable(mapBrowserEvent);
19905 };
19906
19907 /**
19908 * @private
19909 * @type {ol.EventsConditionType}
19910 */
19911 this.condition_ = options.condition !== undefined ?
19912 options.condition : this.defaultCondition_;
19913
19914 /**
19915 * @private
19916 * @type {number}
19917 */
19918 this.duration_ = options.duration !== undefined ? options.duration : 100;
19919
19920 /**
19921 * @private
19922 * @type {number}
19923 */
19924 this.pixelDelta_ = options.pixelDelta !== undefined ?
19925 options.pixelDelta : 128;
19926
19927};
19928ol.inherits(ol.interaction.KeyboardPan, ol.interaction.Interaction);
19929
19930/**
19931 * Handles the {@link ol.MapBrowserEvent map browser event} if it was a
19932 * `KeyEvent`, and decides the direction to pan to (if an arrow key was
19933 * pressed).
19934 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
19935 * @return {boolean} `false` to stop event propagation.
19936 * @this {ol.interaction.KeyboardPan}
19937 * @api
19938 */
19939ol.interaction.KeyboardPan.handleEvent = function(mapBrowserEvent) {
19940 var stopEvent = false;
19941 if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN) {
19942 var keyEvent = mapBrowserEvent.originalEvent;
19943 var keyCode = keyEvent.keyCode;
19944 if (this.condition_(mapBrowserEvent) &&
19945 (keyCode == ol.events.KeyCode.DOWN ||
19946 keyCode == ol.events.KeyCode.LEFT ||
19947 keyCode == ol.events.KeyCode.RIGHT ||
19948 keyCode == ol.events.KeyCode.UP)) {
19949 var map = mapBrowserEvent.map;
19950 var view = map.getView();
19951 var mapUnitsDelta = view.getResolution() * this.pixelDelta_;
19952 var deltaX = 0, deltaY = 0;
19953 if (keyCode == ol.events.KeyCode.DOWN) {
19954 deltaY = -mapUnitsDelta;
19955 } else if (keyCode == ol.events.KeyCode.LEFT) {
19956 deltaX = -mapUnitsDelta;
19957 } else if (keyCode == ol.events.KeyCode.RIGHT) {
19958 deltaX = mapUnitsDelta;
19959 } else {
19960 deltaY = mapUnitsDelta;
19961 }
19962 var delta = [deltaX, deltaY];
19963 ol.coordinate.rotate(delta, view.getRotation());
19964 ol.interaction.Interaction.pan(view, delta, this.duration_);
19965 mapBrowserEvent.preventDefault();
19966 stopEvent = true;
19967 }
19968 }
19969 return !stopEvent;
19970};
19971
19972goog.provide('ol.interaction.KeyboardZoom');
19973
19974goog.require('ol');
19975goog.require('ol.events.EventType');
19976goog.require('ol.events.condition');
19977goog.require('ol.interaction.Interaction');
19978
19979
19980/**
19981 * @classdesc
19982 * Allows the user to zoom the map using keyboard + and -.
19983 * Note that, although this interaction is by default included in maps,
19984 * the keys can only be used when browser focus is on the element to which
19985 * the keyboard events are attached. By default, this is the map div,
19986 * though you can change this with the `keyboardEventTarget` in
19987 * {@link ol.Map}. `document` never loses focus but, for any other element,
19988 * focus will have to be on, and returned to, this element if the keys are to
19989 * function.
19990 * See also {@link ol.interaction.KeyboardPan}.
19991 *
19992 * @constructor
19993 * @param {olx.interaction.KeyboardZoomOptions=} opt_options Options.
19994 * @extends {ol.interaction.Interaction}
19995 * @api
19996 */
19997ol.interaction.KeyboardZoom = function(opt_options) {
19998
19999 ol.interaction.Interaction.call(this, {
20000 handleEvent: ol.interaction.KeyboardZoom.handleEvent
20001 });
20002
20003 var options = opt_options ? opt_options : {};
20004
20005 /**
20006 * @private
20007 * @type {ol.EventsConditionType}
20008 */
20009 this.condition_ = options.condition ? options.condition :
20010 ol.events.condition.targetNotEditable;
20011
20012 /**
20013 * @private
20014 * @type {number}
20015 */
20016 this.delta_ = options.delta ? options.delta : 1;
20017
20018 /**
20019 * @private
20020 * @type {number}
20021 */
20022 this.duration_ = options.duration !== undefined ? options.duration : 100;
20023
20024};
20025ol.inherits(ol.interaction.KeyboardZoom, ol.interaction.Interaction);
20026
20027
20028/**
20029 * Handles the {@link ol.MapBrowserEvent map browser event} if it was a
20030 * `KeyEvent`, and decides whether to zoom in or out (depending on whether the
20031 * key pressed was '+' or '-').
20032 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
20033 * @return {boolean} `false` to stop event propagation.
20034 * @this {ol.interaction.KeyboardZoom}
20035 * @api
20036 */
20037ol.interaction.KeyboardZoom.handleEvent = function(mapBrowserEvent) {
20038 var stopEvent = false;
20039 if (mapBrowserEvent.type == ol.events.EventType.KEYDOWN ||
20040 mapBrowserEvent.type == ol.events.EventType.KEYPRESS) {
20041 var keyEvent = mapBrowserEvent.originalEvent;
20042 var charCode = keyEvent.charCode;
20043 if (this.condition_(mapBrowserEvent) &&
20044 (charCode == '+'.charCodeAt(0) || charCode == '-'.charCodeAt(0))) {
20045 var map = mapBrowserEvent.map;
20046 var delta = (charCode == '+'.charCodeAt(0)) ? this.delta_ : -this.delta_;
20047 var view = map.getView();
20048 ol.interaction.Interaction.zoomByDelta(
20049 view, delta, undefined, this.duration_);
20050 mapBrowserEvent.preventDefault();
20051 stopEvent = true;
20052 }
20053 }
20054 return !stopEvent;
20055};
20056
20057goog.provide('ol.interaction.MouseWheelZoom');
20058
20059goog.require('ol');
20060goog.require('ol.ViewHint');
20061goog.require('ol.easing');
20062goog.require('ol.events.EventType');
20063goog.require('ol.has');
20064goog.require('ol.interaction.Interaction');
20065goog.require('ol.math');
20066
20067
20068/**
20069 * @classdesc
20070 * Allows the user to zoom the map by scrolling the mouse wheel.
20071 *
20072 * @constructor
20073 * @extends {ol.interaction.Interaction}
20074 * @param {olx.interaction.MouseWheelZoomOptions=} opt_options Options.
20075 * @api
20076 */
20077ol.interaction.MouseWheelZoom = function(opt_options) {
20078
20079 ol.interaction.Interaction.call(this, {
20080 handleEvent: ol.interaction.MouseWheelZoom.handleEvent
20081 });
20082
20083 var options = opt_options || {};
20084
20085 /**
20086 * @private
20087 * @type {number}
20088 */
20089 this.delta_ = 0;
20090
20091 /**
20092 * @private
20093 * @type {number}
20094 */
20095 this.duration_ = options.duration !== undefined ? options.duration : 250;
20096
20097 /**
20098 * @private
20099 * @type {number}
20100 */
20101 this.timeout_ = options.timeout !== undefined ? options.timeout : 80;
20102
20103 /**
20104 * @private
20105 * @type {boolean}
20106 */
20107 this.useAnchor_ = options.useAnchor !== undefined ? options.useAnchor : true;
20108
20109 /**
20110 * @private
20111 * @type {boolean}
20112 */
20113 this.constrainResolution_ = options.constrainResolution || false;
20114
20115 /**
20116 * @private
20117 * @type {?ol.Coordinate}
20118 */
20119 this.lastAnchor_ = null;
20120
20121 /**
20122 * @private
20123 * @type {number|undefined}
20124 */
20125 this.startTime_ = undefined;
20126
20127 /**
20128 * @private
20129 * @type {number|undefined}
20130 */
20131 this.timeoutId_ = undefined;
20132
20133 /**
20134 * @private
20135 * @type {ol.interaction.MouseWheelZoom.Mode_|undefined}
20136 */
20137 this.mode_ = undefined;
20138
20139 /**
20140 * Trackpad events separated by this delay will be considered separate
20141 * interactions.
20142 * @type {number}
20143 */
20144 this.trackpadEventGap_ = 400;
20145
20146 /**
20147 * @type {number|undefined}
20148 */
20149 this.trackpadTimeoutId_ = undefined;
20150
20151 /**
20152 * The number of delta values per zoom level
20153 * @private
20154 * @type {number}
20155 */
20156 this.trackpadDeltaPerZoom_ = 300;
20157
20158 /**
20159 * The zoom factor by which scroll zooming is allowed to exceed the limits.
20160 * @private
20161 * @type {number}
20162 */
20163 this.trackpadZoomBuffer_ = 1.5;
20164
20165};
20166ol.inherits(ol.interaction.MouseWheelZoom, ol.interaction.Interaction);
20167
20168
20169/**
20170 * Handles the {@link ol.MapBrowserEvent map browser event} (if it was a
20171 * mousewheel-event) and eventually zooms the map.
20172 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
20173 * @return {boolean} Allow event propagation.
20174 * @this {ol.interaction.MouseWheelZoom}
20175 * @api
20176 */
20177ol.interaction.MouseWheelZoom.handleEvent = function(mapBrowserEvent) {
20178 var type = mapBrowserEvent.type;
20179 if (type !== ol.events.EventType.WHEEL && type !== ol.events.EventType.MOUSEWHEEL) {
20180 return true;
20181 }
20182
20183 mapBrowserEvent.preventDefault();
20184
20185 var map = mapBrowserEvent.map;
20186 var wheelEvent = /** @type {WheelEvent} */ (mapBrowserEvent.originalEvent);
20187
20188 if (this.useAnchor_) {
20189 this.lastAnchor_ = mapBrowserEvent.coordinate;
20190 }
20191
20192 // Delta normalisation inspired by
20193 // https://github.com/mapbox/mapbox-gl-js/blob/001c7b9/js/ui/handler/scroll_zoom.js
20194 var delta;
20195 if (mapBrowserEvent.type == ol.events.EventType.WHEEL) {
20196 delta = wheelEvent.deltaY;
20197 if (ol.has.FIREFOX &&
20198 wheelEvent.deltaMode === WheelEvent.DOM_DELTA_PIXEL) {
20199 delta /= ol.has.DEVICE_PIXEL_RATIO;
20200 }
20201 if (wheelEvent.deltaMode === WheelEvent.DOM_DELTA_LINE) {
20202 delta *= 40;
20203 }
20204 } else if (mapBrowserEvent.type == ol.events.EventType.MOUSEWHEEL) {
20205 delta = -wheelEvent.wheelDeltaY;
20206 if (ol.has.SAFARI) {
20207 delta /= 3;
20208 }
20209 }
20210
20211 if (delta === 0) {
20212 return false;
20213 }
20214
20215 var now = Date.now();
20216
20217 if (this.startTime_ === undefined) {
20218 this.startTime_ = now;
20219 }
20220
20221 if (!this.mode_ || now - this.startTime_ > this.trackpadEventGap_) {
20222 this.mode_ = Math.abs(delta) < 4 ?
20223 ol.interaction.MouseWheelZoom.Mode_.TRACKPAD :
20224 ol.interaction.MouseWheelZoom.Mode_.WHEEL;
20225 }
20226
20227 if (this.mode_ === ol.interaction.MouseWheelZoom.Mode_.TRACKPAD) {
20228 var view = map.getView();
20229 if (this.trackpadTimeoutId_) {
20230 clearTimeout(this.trackpadTimeoutId_);
20231 } else {
20232 view.setHint(ol.ViewHint.INTERACTING, 1);
20233 }
20234 this.trackpadTimeoutId_ = setTimeout(this.decrementInteractingHint_.bind(this), this.trackpadEventGap_);
20235 var resolution = view.getResolution() * Math.pow(2, delta / this.trackpadDeltaPerZoom_);
20236 var minResolution = view.getMinResolution();
20237 var maxResolution = view.getMaxResolution();
20238 var rebound = 0;
20239 if (resolution < minResolution) {
20240 resolution = Math.max(resolution, minResolution / this.trackpadZoomBuffer_);
20241 rebound = 1;
20242 } else if (resolution > maxResolution) {
20243 resolution = Math.min(resolution, maxResolution * this.trackpadZoomBuffer_);
20244 rebound = -1;
20245 }
20246 if (this.lastAnchor_) {
20247 var center = view.calculateCenterZoom(resolution, this.lastAnchor_);
20248 view.setCenter(view.constrainCenter(center));
20249 }
20250 view.setResolution(resolution);
20251
20252 if (rebound === 0 && this.constrainResolution_) {
20253 view.animate({
20254 resolution: view.constrainResolution(resolution, delta > 0 ? -1 : 1),
20255 easing: ol.easing.easeOut,
20256 anchor: this.lastAnchor_,
20257 duration: this.duration_
20258 });
20259 }
20260
20261 if (rebound > 0) {
20262 view.animate({
20263 resolution: minResolution,
20264 easing: ol.easing.easeOut,
20265 anchor: this.lastAnchor_,
20266 duration: 500
20267 });
20268 } else if (rebound < 0) {
20269 view.animate({
20270 resolution: maxResolution,
20271 easing: ol.easing.easeOut,
20272 anchor: this.lastAnchor_,
20273 duration: 500
20274 });
20275 }
20276 this.startTime_ = now;
20277 return false;
20278 }
20279
20280 this.delta_ += delta;
20281
20282 var timeLeft = Math.max(this.timeout_ - (now - this.startTime_), 0);
20283
20284 clearTimeout(this.timeoutId_);
20285 this.timeoutId_ = setTimeout(this.handleWheelZoom_.bind(this, map), timeLeft);
20286
20287 return false;
20288};
20289
20290
20291/**
20292 * @private
20293 */
20294ol.interaction.MouseWheelZoom.prototype.decrementInteractingHint_ = function() {
20295 this.trackpadTimeoutId_ = undefined;
20296 var view = this.getMap().getView();
20297 view.setHint(ol.ViewHint.INTERACTING, -1);
20298};
20299
20300
20301/**
20302 * @private
20303 * @param {ol.Map} map Map.
20304 */
20305ol.interaction.MouseWheelZoom.prototype.handleWheelZoom_ = function(map) {
20306 var view = map.getView();
20307 if (view.getAnimating()) {
20308 view.cancelAnimations();
20309 }
20310 var maxDelta = ol.MOUSEWHEELZOOM_MAXDELTA;
20311 var delta = ol.math.clamp(this.delta_, -maxDelta, maxDelta);
20312 ol.interaction.Interaction.zoomByDelta(view, -delta, this.lastAnchor_,
20313 this.duration_);
20314 this.mode_ = undefined;
20315 this.delta_ = 0;
20316 this.lastAnchor_ = null;
20317 this.startTime_ = undefined;
20318 this.timeoutId_ = undefined;
20319};
20320
20321
20322/**
20323 * Enable or disable using the mouse's location as an anchor when zooming
20324 * @param {boolean} useAnchor true to zoom to the mouse's location, false
20325 * to zoom to the center of the map
20326 * @api
20327 */
20328ol.interaction.MouseWheelZoom.prototype.setMouseAnchor = function(useAnchor) {
20329 this.useAnchor_ = useAnchor;
20330 if (!useAnchor) {
20331 this.lastAnchor_ = null;
20332 }
20333};
20334
20335
20336/**
20337 * @enum {string}
20338 * @private
20339 */
20340ol.interaction.MouseWheelZoom.Mode_ = {
20341 TRACKPAD: 'trackpad',
20342 WHEEL: 'wheel'
20343};
20344
20345goog.provide('ol.interaction.PinchRotate');
20346
20347goog.require('ol');
20348goog.require('ol.ViewHint');
20349goog.require('ol.functions');
20350goog.require('ol.interaction.Interaction');
20351goog.require('ol.interaction.Pointer');
20352goog.require('ol.RotationConstraint');
20353
20354
20355/**
20356 * @classdesc
20357 * Allows the user to rotate the map by twisting with two fingers
20358 * on a touch screen.
20359 *
20360 * @constructor
20361 * @extends {ol.interaction.Pointer}
20362 * @param {olx.interaction.PinchRotateOptions=} opt_options Options.
20363 * @api
20364 */
20365ol.interaction.PinchRotate = function(opt_options) {
20366
20367 ol.interaction.Pointer.call(this, {
20368 handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_,
20369 handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_,
20370 handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_
20371 });
20372
20373 var options = opt_options || {};
20374
20375 /**
20376 * @private
20377 * @type {ol.Coordinate}
20378 */
20379 this.anchor_ = null;
20380
20381 /**
20382 * @private
20383 * @type {number|undefined}
20384 */
20385 this.lastAngle_ = undefined;
20386
20387 /**
20388 * @private
20389 * @type {boolean}
20390 */
20391 this.rotating_ = false;
20392
20393 /**
20394 * @private
20395 * @type {number}
20396 */
20397 this.rotationDelta_ = 0.0;
20398
20399 /**
20400 * @private
20401 * @type {number}
20402 */
20403 this.threshold_ = options.threshold !== undefined ? options.threshold : 0.3;
20404
20405 /**
20406 * @private
20407 * @type {number}
20408 */
20409 this.duration_ = options.duration !== undefined ? options.duration : 250;
20410
20411};
20412ol.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer);
20413
20414
20415/**
20416 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20417 * @this {ol.interaction.PinchRotate}
20418 * @private
20419 */
20420ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) {
20421 var rotationDelta = 0.0;
20422
20423 var touch0 = this.targetPointers[0];
20424 var touch1 = this.targetPointers[1];
20425
20426 // angle between touches
20427 var angle = Math.atan2(
20428 touch1.clientY - touch0.clientY,
20429 touch1.clientX - touch0.clientX);
20430
20431 if (this.lastAngle_ !== undefined) {
20432 var delta = angle - this.lastAngle_;
20433 this.rotationDelta_ += delta;
20434 if (!this.rotating_ &&
20435 Math.abs(this.rotationDelta_) > this.threshold_) {
20436 this.rotating_ = true;
20437 }
20438 rotationDelta = delta;
20439 }
20440 this.lastAngle_ = angle;
20441
20442 var map = mapBrowserEvent.map;
20443 var view = map.getView();
20444 if (view.getConstraints().rotation === ol.RotationConstraint.disable) {
20445 return;
20446 }
20447
20448 // rotate anchor point.
20449 // FIXME: should be the intersection point between the lines:
20450 // touch0,touch1 and previousTouch0,previousTouch1
20451 var viewportPosition = map.getViewport().getBoundingClientRect();
20452 var centroid = ol.interaction.Pointer.centroid(this.targetPointers);
20453 centroid[0] -= viewportPosition.left;
20454 centroid[1] -= viewportPosition.top;
20455 this.anchor_ = map.getCoordinateFromPixel(centroid);
20456
20457 // rotate
20458 if (this.rotating_) {
20459 var rotation = view.getRotation();
20460 map.render();
20461 ol.interaction.Interaction.rotateWithoutConstraints(view,
20462 rotation + rotationDelta, this.anchor_);
20463 }
20464};
20465
20466
20467/**
20468 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20469 * @return {boolean} Stop drag sequence?
20470 * @this {ol.interaction.PinchRotate}
20471 * @private
20472 */
20473ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) {
20474 if (this.targetPointers.length < 2) {
20475 var map = mapBrowserEvent.map;
20476 var view = map.getView();
20477 view.setHint(ol.ViewHint.INTERACTING, -1);
20478 if (this.rotating_) {
20479 var rotation = view.getRotation();
20480 ol.interaction.Interaction.rotate(
20481 view, rotation, this.anchor_, this.duration_);
20482 }
20483 return false;
20484 } else {
20485 return true;
20486 }
20487};
20488
20489
20490/**
20491 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20492 * @return {boolean} Start drag sequence?
20493 * @this {ol.interaction.PinchRotate}
20494 * @private
20495 */
20496ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) {
20497 if (this.targetPointers.length >= 2) {
20498 var map = mapBrowserEvent.map;
20499 this.anchor_ = null;
20500 this.lastAngle_ = undefined;
20501 this.rotating_ = false;
20502 this.rotationDelta_ = 0.0;
20503 if (!this.handlingDownUpSequence) {
20504 map.getView().setHint(ol.ViewHint.INTERACTING, 1);
20505 }
20506 return true;
20507 } else {
20508 return false;
20509 }
20510};
20511
20512
20513/**
20514 * @inheritDoc
20515 */
20516ol.interaction.PinchRotate.prototype.shouldStopEvent = ol.functions.FALSE;
20517
20518goog.provide('ol.interaction.PinchZoom');
20519
20520goog.require('ol');
20521goog.require('ol.ViewHint');
20522goog.require('ol.functions');
20523goog.require('ol.interaction.Interaction');
20524goog.require('ol.interaction.Pointer');
20525
20526
20527/**
20528 * @classdesc
20529 * Allows the user to zoom the map by pinching with two fingers
20530 * on a touch screen.
20531 *
20532 * @constructor
20533 * @extends {ol.interaction.Pointer}
20534 * @param {olx.interaction.PinchZoomOptions=} opt_options Options.
20535 * @api
20536 */
20537ol.interaction.PinchZoom = function(opt_options) {
20538
20539 ol.interaction.Pointer.call(this, {
20540 handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_,
20541 handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_,
20542 handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_
20543 });
20544
20545 var options = opt_options ? opt_options : {};
20546
20547 /**
20548 * @private
20549 * @type {boolean}
20550 */
20551 this.constrainResolution_ = options.constrainResolution || false;
20552
20553 /**
20554 * @private
20555 * @type {ol.Coordinate}
20556 */
20557 this.anchor_ = null;
20558
20559 /**
20560 * @private
20561 * @type {number}
20562 */
20563 this.duration_ = options.duration !== undefined ? options.duration : 400;
20564
20565 /**
20566 * @private
20567 * @type {number|undefined}
20568 */
20569 this.lastDistance_ = undefined;
20570
20571 /**
20572 * @private
20573 * @type {number}
20574 */
20575 this.lastScaleDelta_ = 1;
20576
20577};
20578ol.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer);
20579
20580
20581/**
20582 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20583 * @this {ol.interaction.PinchZoom}
20584 * @private
20585 */
20586ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) {
20587 var scaleDelta = 1.0;
20588
20589 var touch0 = this.targetPointers[0];
20590 var touch1 = this.targetPointers[1];
20591 var dx = touch0.clientX - touch1.clientX;
20592 var dy = touch0.clientY - touch1.clientY;
20593
20594 // distance between touches
20595 var distance = Math.sqrt(dx * dx + dy * dy);
20596
20597 if (this.lastDistance_ !== undefined) {
20598 scaleDelta = this.lastDistance_ / distance;
20599 }
20600 this.lastDistance_ = distance;
20601
20602
20603 var map = mapBrowserEvent.map;
20604 var view = map.getView();
20605 var resolution = view.getResolution();
20606 var maxResolution = view.getMaxResolution();
20607 var minResolution = view.getMinResolution();
20608 var newResolution = resolution * scaleDelta;
20609 if (newResolution > maxResolution) {
20610 scaleDelta = maxResolution / resolution;
20611 newResolution = maxResolution;
20612 } else if (newResolution < minResolution) {
20613 scaleDelta = minResolution / resolution;
20614 newResolution = minResolution;
20615 }
20616
20617 if (scaleDelta != 1.0) {
20618 this.lastScaleDelta_ = scaleDelta;
20619 }
20620
20621 // scale anchor point.
20622 var viewportPosition = map.getViewport().getBoundingClientRect();
20623 var centroid = ol.interaction.Pointer.centroid(this.targetPointers);
20624 centroid[0] -= viewportPosition.left;
20625 centroid[1] -= viewportPosition.top;
20626 this.anchor_ = map.getCoordinateFromPixel(centroid);
20627
20628 // scale, bypass the resolution constraint
20629 map.render();
20630 ol.interaction.Interaction.zoomWithoutConstraints(view, newResolution, this.anchor_);
20631};
20632
20633
20634/**
20635 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20636 * @return {boolean} Stop drag sequence?
20637 * @this {ol.interaction.PinchZoom}
20638 * @private
20639 */
20640ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) {
20641 if (this.targetPointers.length < 2) {
20642 var map = mapBrowserEvent.map;
20643 var view = map.getView();
20644 view.setHint(ol.ViewHint.INTERACTING, -1);
20645 var resolution = view.getResolution();
20646 if (this.constrainResolution_ ||
20647 resolution < view.getMinResolution() ||
20648 resolution > view.getMaxResolution()) {
20649 // Zoom to final resolution, with an animation, and provide a
20650 // direction not to zoom out/in if user was pinching in/out.
20651 // Direction is > 0 if pinching out, and < 0 if pinching in.
20652 var direction = this.lastScaleDelta_ - 1;
20653 ol.interaction.Interaction.zoom(view, resolution,
20654 this.anchor_, this.duration_, direction);
20655 }
20656 return false;
20657 } else {
20658 return true;
20659 }
20660};
20661
20662
20663/**
20664 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
20665 * @return {boolean} Start drag sequence?
20666 * @this {ol.interaction.PinchZoom}
20667 * @private
20668 */
20669ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) {
20670 if (this.targetPointers.length >= 2) {
20671 var map = mapBrowserEvent.map;
20672 this.anchor_ = null;
20673 this.lastDistance_ = undefined;
20674 this.lastScaleDelta_ = 1;
20675 if (!this.handlingDownUpSequence) {
20676 map.getView().setHint(ol.ViewHint.INTERACTING, 1);
20677 }
20678 return true;
20679 } else {
20680 return false;
20681 }
20682};
20683
20684
20685/**
20686 * @inheritDoc
20687 */
20688ol.interaction.PinchZoom.prototype.shouldStopEvent = ol.functions.FALSE;
20689
20690goog.provide('ol.interaction');
20691
20692goog.require('ol.Collection');
20693goog.require('ol.Kinetic');
20694goog.require('ol.interaction.DoubleClickZoom');
20695goog.require('ol.interaction.DragPan');
20696goog.require('ol.interaction.DragRotate');
20697goog.require('ol.interaction.DragZoom');
20698goog.require('ol.interaction.KeyboardPan');
20699goog.require('ol.interaction.KeyboardZoom');
20700goog.require('ol.interaction.MouseWheelZoom');
20701goog.require('ol.interaction.PinchRotate');
20702goog.require('ol.interaction.PinchZoom');
20703
20704
20705/**
20706 * Set of interactions included in maps by default. Specific interactions can be
20707 * excluded by setting the appropriate option to false in the constructor
20708 * options, but the order of the interactions is fixed. If you want to specify
20709 * a different order for interactions, you will need to create your own
20710 * {@link ol.interaction.Interaction} instances and insert them into a
20711 * {@link ol.Collection} in the order you want before creating your
20712 * {@link ol.Map} instance. The default set of interactions, in sequence, is:
20713 * * {@link ol.interaction.DragRotate}
20714 * * {@link ol.interaction.DoubleClickZoom}
20715 * * {@link ol.interaction.DragPan}
20716 * * {@link ol.interaction.PinchRotate}
20717 * * {@link ol.interaction.PinchZoom}
20718 * * {@link ol.interaction.KeyboardPan}
20719 * * {@link ol.interaction.KeyboardZoom}
20720 * * {@link ol.interaction.MouseWheelZoom}
20721 * * {@link ol.interaction.DragZoom}
20722 *
20723 * @param {olx.interaction.DefaultsOptions=} opt_options Defaults options.
20724 * @return {ol.Collection.<ol.interaction.Interaction>} A collection of
20725 * interactions to be used with the ol.Map constructor's interactions option.
20726 * @api
20727 */
20728ol.interaction.defaults = function(opt_options) {
20729
20730 var options = opt_options ? opt_options : {};
20731
20732 var interactions = new ol.Collection();
20733
20734 var kinetic = new ol.Kinetic(-0.005, 0.05, 100);
20735
20736 var altShiftDragRotate = options.altShiftDragRotate !== undefined ?
20737 options.altShiftDragRotate : true;
20738 if (altShiftDragRotate) {
20739 interactions.push(new ol.interaction.DragRotate());
20740 }
20741
20742 var doubleClickZoom = options.doubleClickZoom !== undefined ?
20743 options.doubleClickZoom : true;
20744 if (doubleClickZoom) {
20745 interactions.push(new ol.interaction.DoubleClickZoom({
20746 delta: options.zoomDelta,
20747 duration: options.zoomDuration
20748 }));
20749 }
20750
20751 var dragPan = options.dragPan !== undefined ? options.dragPan : true;
20752 if (dragPan) {
20753 interactions.push(new ol.interaction.DragPan({
20754 kinetic: kinetic
20755 }));
20756 }
20757
20758 var pinchRotate = options.pinchRotate !== undefined ? options.pinchRotate :
20759 true;
20760 if (pinchRotate) {
20761 interactions.push(new ol.interaction.PinchRotate());
20762 }
20763
20764 var pinchZoom = options.pinchZoom !== undefined ? options.pinchZoom : true;
20765 if (pinchZoom) {
20766 interactions.push(new ol.interaction.PinchZoom({
20767 constrainResolution: options.constrainResolution,
20768 duration: options.zoomDuration
20769 }));
20770 }
20771
20772 var keyboard = options.keyboard !== undefined ? options.keyboard : true;
20773 if (keyboard) {
20774 interactions.push(new ol.interaction.KeyboardPan());
20775 interactions.push(new ol.interaction.KeyboardZoom({
20776 delta: options.zoomDelta,
20777 duration: options.zoomDuration
20778 }));
20779 }
20780
20781 var mouseWheelZoom = options.mouseWheelZoom !== undefined ?
20782 options.mouseWheelZoom : true;
20783 if (mouseWheelZoom) {
20784 interactions.push(new ol.interaction.MouseWheelZoom({
20785 constrainResolution: options.constrainResolution,
20786 duration: options.zoomDuration
20787 }));
20788 }
20789
20790 var shiftDragZoom = options.shiftDragZoom !== undefined ?
20791 options.shiftDragZoom : true;
20792 if (shiftDragZoom) {
20793 interactions.push(new ol.interaction.DragZoom({
20794 duration: options.zoomDuration
20795 }));
20796 }
20797
20798 return interactions;
20799
20800};
20801
20802goog.provide('ol.layer.Property');
20803
20804/**
20805 * @enum {string}
20806 */
20807ol.layer.Property = {
20808 OPACITY: 'opacity',
20809 VISIBLE: 'visible',
20810 EXTENT: 'extent',
20811 Z_INDEX: 'zIndex',
20812 MAX_RESOLUTION: 'maxResolution',
20813 MIN_RESOLUTION: 'minResolution',
20814 SOURCE: 'source'
20815};
20816
20817goog.provide('ol.layer.Base');
20818
20819goog.require('ol');
20820goog.require('ol.Object');
20821goog.require('ol.layer.Property');
20822goog.require('ol.math');
20823goog.require('ol.obj');
20824
20825
20826/**
20827 * @classdesc
20828 * Abstract base class; normally only used for creating subclasses and not
20829 * instantiated in apps.
20830 * Note that with `ol.layer.Base` and all its subclasses, any property set in
20831 * the options is set as a {@link ol.Object} property on the layer object, so
20832 * is observable, and has get/set accessors.
20833 *
20834 * @constructor
20835 * @abstract
20836 * @extends {ol.Object}
20837 * @param {olx.layer.BaseOptions} options Layer options.
20838 * @api
20839 */
20840ol.layer.Base = function(options) {
20841
20842 ol.Object.call(this);
20843
20844 /**
20845 * @type {Object.<string, *>}
20846 */
20847 var properties = ol.obj.assign({}, options);
20848 properties[ol.layer.Property.OPACITY] =
20849 options.opacity !== undefined ? options.opacity : 1;
20850 properties[ol.layer.Property.VISIBLE] =
20851 options.visible !== undefined ? options.visible : true;
20852 properties[ol.layer.Property.Z_INDEX] =
20853 options.zIndex !== undefined ? options.zIndex : 0;
20854 properties[ol.layer.Property.MAX_RESOLUTION] =
20855 options.maxResolution !== undefined ? options.maxResolution : Infinity;
20856 properties[ol.layer.Property.MIN_RESOLUTION] =
20857 options.minResolution !== undefined ? options.minResolution : 0;
20858
20859 this.setProperties(properties);
20860
20861 /**
20862 * @type {ol.LayerState}
20863 * @private
20864 */
20865 this.state_ = /** @type {ol.LayerState} */ ({
20866 layer: /** @type {ol.layer.Layer} */ (this),
20867 managed: true
20868 });
20869
20870};
20871ol.inherits(ol.layer.Base, ol.Object);
20872
20873
20874/**
20875 * Create a renderer for this layer.
20876 * @abstract
20877 * @param {ol.renderer.Map} mapRenderer The map renderer.
20878 * @return {ol.renderer.Layer} A layer renderer.
20879 */
20880ol.layer.Base.prototype.createRenderer = function(mapRenderer) {};
20881
20882
20883/**
20884 * @return {ol.LayerState} Layer state.
20885 */
20886ol.layer.Base.prototype.getLayerState = function() {
20887 this.state_.opacity = ol.math.clamp(this.getOpacity(), 0, 1);
20888 this.state_.sourceState = this.getSourceState();
20889 this.state_.visible = this.getVisible();
20890 this.state_.extent = this.getExtent();
20891 this.state_.zIndex = this.getZIndex();
20892 this.state_.maxResolution = this.getMaxResolution();
20893 this.state_.minResolution = Math.max(this.getMinResolution(), 0);
20894
20895 return this.state_;
20896};
20897
20898
20899/**
20900 * @abstract
20901 * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be
20902 * modified in place).
20903 * @return {Array.<ol.layer.Layer>} Array of layers.
20904 */
20905ol.layer.Base.prototype.getLayersArray = function(opt_array) {};
20906
20907
20908/**
20909 * @abstract
20910 * @param {Array.<ol.LayerState>=} opt_states Optional list of layer
20911 * states (to be modified in place).
20912 * @return {Array.<ol.LayerState>} List of layer states.
20913 */
20914ol.layer.Base.prototype.getLayerStatesArray = function(opt_states) {};
20915
20916
20917/**
20918 * Return the {@link ol.Extent extent} of the layer or `undefined` if it
20919 * will be visible regardless of extent.
20920 * @return {ol.Extent|undefined} The layer extent.
20921 * @observable
20922 * @api
20923 */
20924ol.layer.Base.prototype.getExtent = function() {
20925 return /** @type {ol.Extent|undefined} */ (
20926 this.get(ol.layer.Property.EXTENT));
20927};
20928
20929
20930/**
20931 * Return the maximum resolution of the layer.
20932 * @return {number} The maximum resolution of the layer.
20933 * @observable
20934 * @api
20935 */
20936ol.layer.Base.prototype.getMaxResolution = function() {
20937 return /** @type {number} */ (
20938 this.get(ol.layer.Property.MAX_RESOLUTION));
20939};
20940
20941
20942/**
20943 * Return the minimum resolution of the layer.
20944 * @return {number} The minimum resolution of the layer.
20945 * @observable
20946 * @api
20947 */
20948ol.layer.Base.prototype.getMinResolution = function() {
20949 return /** @type {number} */ (
20950 this.get(ol.layer.Property.MIN_RESOLUTION));
20951};
20952
20953
20954/**
20955 * Return the opacity of the layer (between 0 and 1).
20956 * @return {number} The opacity of the layer.
20957 * @observable
20958 * @api
20959 */
20960ol.layer.Base.prototype.getOpacity = function() {
20961 return /** @type {number} */ (this.get(ol.layer.Property.OPACITY));
20962};
20963
20964
20965/**
20966 * @abstract
20967 * @return {ol.source.State} Source state.
20968 */
20969ol.layer.Base.prototype.getSourceState = function() {};
20970
20971
20972/**
20973 * Return the visibility of the layer (`true` or `false`).
20974 * @return {boolean} The visibility of the layer.
20975 * @observable
20976 * @api
20977 */
20978ol.layer.Base.prototype.getVisible = function() {
20979 return /** @type {boolean} */ (this.get(ol.layer.Property.VISIBLE));
20980};
20981
20982
20983/**
20984 * Return the Z-index of the layer, which is used to order layers before
20985 * rendering. The default Z-index is 0.
20986 * @return {number} The Z-index of the layer.
20987 * @observable
20988 * @api
20989 */
20990ol.layer.Base.prototype.getZIndex = function() {
20991 return /** @type {number} */ (this.get(ol.layer.Property.Z_INDEX));
20992};
20993
20994
20995/**
20996 * Set the extent at which the layer is visible. If `undefined`, the layer
20997 * will be visible at all extents.
20998 * @param {ol.Extent|undefined} extent The extent of the layer.
20999 * @observable
21000 * @api
21001 */
21002ol.layer.Base.prototype.setExtent = function(extent) {
21003 this.set(ol.layer.Property.EXTENT, extent);
21004};
21005
21006
21007/**
21008 * Set the maximum resolution at which the layer is visible.
21009 * @param {number} maxResolution The maximum resolution of the layer.
21010 * @observable
21011 * @api
21012 */
21013ol.layer.Base.prototype.setMaxResolution = function(maxResolution) {
21014 this.set(ol.layer.Property.MAX_RESOLUTION, maxResolution);
21015};
21016
21017
21018/**
21019 * Set the minimum resolution at which the layer is visible.
21020 * @param {number} minResolution The minimum resolution of the layer.
21021 * @observable
21022 * @api
21023 */
21024ol.layer.Base.prototype.setMinResolution = function(minResolution) {
21025 this.set(ol.layer.Property.MIN_RESOLUTION, minResolution);
21026};
21027
21028
21029/**
21030 * Set the opacity of the layer, allowed values range from 0 to 1.
21031 * @param {number} opacity The opacity of the layer.
21032 * @observable
21033 * @api
21034 */
21035ol.layer.Base.prototype.setOpacity = function(opacity) {
21036 this.set(ol.layer.Property.OPACITY, opacity);
21037};
21038
21039
21040/**
21041 * Set the visibility of the layer (`true` or `false`).
21042 * @param {boolean} visible The visibility of the layer.
21043 * @observable
21044 * @api
21045 */
21046ol.layer.Base.prototype.setVisible = function(visible) {
21047 this.set(ol.layer.Property.VISIBLE, visible);
21048};
21049
21050
21051/**
21052 * Set Z-index of the layer, which is used to order layers before rendering.
21053 * The default Z-index is 0.
21054 * @param {number} zindex The z-index of the layer.
21055 * @observable
21056 * @api
21057 */
21058ol.layer.Base.prototype.setZIndex = function(zindex) {
21059 this.set(ol.layer.Property.Z_INDEX, zindex);
21060};
21061
21062goog.provide('ol.source.State');
21063
21064
21065/**
21066 * State of the source, one of 'undefined', 'loading', 'ready' or 'error'.
21067 * @enum {string}
21068 */
21069ol.source.State = {
21070 UNDEFINED: 'undefined',
21071 LOADING: 'loading',
21072 READY: 'ready',
21073 ERROR: 'error'
21074};
21075
21076
21077goog.provide('ol.layer.Group');
21078
21079goog.require('ol');
21080goog.require('ol.Collection');
21081goog.require('ol.CollectionEventType');
21082goog.require('ol.Object');
21083goog.require('ol.ObjectEventType');
21084goog.require('ol.asserts');
21085goog.require('ol.events');
21086goog.require('ol.events.EventType');
21087goog.require('ol.extent');
21088goog.require('ol.layer.Base');
21089goog.require('ol.obj');
21090goog.require('ol.source.State');
21091
21092
21093/**
21094 * @classdesc
21095 * A {@link ol.Collection} of layers that are handled together.
21096 *
21097 * A generic `change` event is triggered when the group/Collection changes.
21098 *
21099 * @constructor
21100 * @extends {ol.layer.Base}
21101 * @param {olx.layer.GroupOptions=} opt_options Layer options.
21102 * @api
21103 */
21104ol.layer.Group = function(opt_options) {
21105
21106 var options = opt_options || {};
21107 var baseOptions = /** @type {olx.layer.GroupOptions} */
21108 (ol.obj.assign({}, options));
21109 delete baseOptions.layers;
21110
21111 var layers = options.layers;
21112
21113 ol.layer.Base.call(this, baseOptions);
21114
21115 /**
21116 * @private
21117 * @type {Array.<ol.EventsKey>}
21118 */
21119 this.layersListenerKeys_ = [];
21120
21121 /**
21122 * @private
21123 * @type {Object.<string, Array.<ol.EventsKey>>}
21124 */
21125 this.listenerKeys_ = {};
21126
21127 ol.events.listen(this,
21128 ol.Object.getChangeEventType(ol.layer.Group.Property_.LAYERS),
21129 this.handleLayersChanged_, this);
21130
21131 if (layers) {
21132 if (Array.isArray(layers)) {
21133 layers = new ol.Collection(layers.slice(), {unique: true});
21134 } else {
21135 ol.asserts.assert(layers instanceof ol.Collection,
21136 43); // Expected `layers` to be an array or an `ol.Collection`
21137 layers = layers;
21138 }
21139 } else {
21140 layers = new ol.Collection(undefined, {unique: true});
21141 }
21142
21143 this.setLayers(layers);
21144
21145};
21146ol.inherits(ol.layer.Group, ol.layer.Base);
21147
21148
21149/**
21150 * @inheritDoc
21151 */
21152ol.layer.Group.prototype.createRenderer = function(mapRenderer) {};
21153
21154
21155/**
21156 * @private
21157 */
21158ol.layer.Group.prototype.handleLayerChange_ = function() {
21159 this.changed();
21160};
21161
21162
21163/**
21164 * @param {ol.events.Event} event Event.
21165 * @private
21166 */
21167ol.layer.Group.prototype.handleLayersChanged_ = function(event) {
21168 this.layersListenerKeys_.forEach(ol.events.unlistenByKey);
21169 this.layersListenerKeys_.length = 0;
21170
21171 var layers = this.getLayers();
21172 this.layersListenerKeys_.push(
21173 ol.events.listen(layers, ol.CollectionEventType.ADD,
21174 this.handleLayersAdd_, this),
21175 ol.events.listen(layers, ol.CollectionEventType.REMOVE,
21176 this.handleLayersRemove_, this));
21177
21178 for (var id in this.listenerKeys_) {
21179 this.listenerKeys_[id].forEach(ol.events.unlistenByKey);
21180 }
21181 ol.obj.clear(this.listenerKeys_);
21182
21183 var layersArray = layers.getArray();
21184 var i, ii, layer;
21185 for (i = 0, ii = layersArray.length; i < ii; i++) {
21186 layer = layersArray[i];
21187 this.listenerKeys_[ol.getUid(layer).toString()] = [
21188 ol.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE,
21189 this.handleLayerChange_, this),
21190 ol.events.listen(layer, ol.events.EventType.CHANGE,
21191 this.handleLayerChange_, this)
21192 ];
21193 }
21194
21195 this.changed();
21196};
21197
21198
21199/**
21200 * @param {ol.Collection.Event} collectionEvent Collection event.
21201 * @private
21202 */
21203ol.layer.Group.prototype.handleLayersAdd_ = function(collectionEvent) {
21204 var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
21205 var key = ol.getUid(layer).toString();
21206 this.listenerKeys_[key] = [
21207 ol.events.listen(layer, ol.ObjectEventType.PROPERTYCHANGE,
21208 this.handleLayerChange_, this),
21209 ol.events.listen(layer, ol.events.EventType.CHANGE,
21210 this.handleLayerChange_, this)
21211 ];
21212 this.changed();
21213};
21214
21215
21216/**
21217 * @param {ol.Collection.Event} collectionEvent Collection event.
21218 * @private
21219 */
21220ol.layer.Group.prototype.handleLayersRemove_ = function(collectionEvent) {
21221 var layer = /** @type {ol.layer.Base} */ (collectionEvent.element);
21222 var key = ol.getUid(layer).toString();
21223 this.listenerKeys_[key].forEach(ol.events.unlistenByKey);
21224 delete this.listenerKeys_[key];
21225 this.changed();
21226};
21227
21228
21229/**
21230 * Returns the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
21231 * in this group.
21232 * @return {!ol.Collection.<ol.layer.Base>} Collection of
21233 * {@link ol.layer.Base layers} that are part of this group.
21234 * @observable
21235 * @api
21236 */
21237ol.layer.Group.prototype.getLayers = function() {
21238 return /** @type {!ol.Collection.<ol.layer.Base>} */ (this.get(
21239 ol.layer.Group.Property_.LAYERS));
21240};
21241
21242
21243/**
21244 * Set the {@link ol.Collection collection} of {@link ol.layer.Layer layers}
21245 * in this group.
21246 * @param {!ol.Collection.<ol.layer.Base>} layers Collection of
21247 * {@link ol.layer.Base layers} that are part of this group.
21248 * @observable
21249 * @api
21250 */
21251ol.layer.Group.prototype.setLayers = function(layers) {
21252 this.set(ol.layer.Group.Property_.LAYERS, layers);
21253};
21254
21255
21256/**
21257 * @inheritDoc
21258 */
21259ol.layer.Group.prototype.getLayersArray = function(opt_array) {
21260 var array = opt_array !== undefined ? opt_array : [];
21261 this.getLayers().forEach(function(layer) {
21262 layer.getLayersArray(array);
21263 });
21264 return array;
21265};
21266
21267
21268/**
21269 * @inheritDoc
21270 */
21271ol.layer.Group.prototype.getLayerStatesArray = function(opt_states) {
21272 var states = opt_states !== undefined ? opt_states : [];
21273
21274 var pos = states.length;
21275
21276 this.getLayers().forEach(function(layer) {
21277 layer.getLayerStatesArray(states);
21278 });
21279
21280 var ownLayerState = this.getLayerState();
21281 var i, ii, layerState;
21282 for (i = pos, ii = states.length; i < ii; i++) {
21283 layerState = states[i];
21284 layerState.opacity *= ownLayerState.opacity;
21285 layerState.visible = layerState.visible && ownLayerState.visible;
21286 layerState.maxResolution = Math.min(
21287 layerState.maxResolution, ownLayerState.maxResolution);
21288 layerState.minResolution = Math.max(
21289 layerState.minResolution, ownLayerState.minResolution);
21290 if (ownLayerState.extent !== undefined) {
21291 if (layerState.extent !== undefined) {
21292 layerState.extent = ol.extent.getIntersection(
21293 layerState.extent, ownLayerState.extent);
21294 } else {
21295 layerState.extent = ownLayerState.extent;
21296 }
21297 }
21298 }
21299
21300 return states;
21301};
21302
21303
21304/**
21305 * @inheritDoc
21306 */
21307ol.layer.Group.prototype.getSourceState = function() {
21308 return ol.source.State.READY;
21309};
21310
21311/**
21312 * @enum {string}
21313 * @private
21314 */
21315ol.layer.Group.Property_ = {
21316 LAYERS: 'layers'
21317};
21318
21319goog.provide('ol.render.EventType');
21320
21321/**
21322 * @enum {string}
21323 */
21324ol.render.EventType = {
21325 /**
21326 * @event ol.render.Event#postcompose
21327 * @api
21328 */
21329 POSTCOMPOSE: 'postcompose',
21330 /**
21331 * @event ol.render.Event#precompose
21332 * @api
21333 */
21334 PRECOMPOSE: 'precompose',
21335 /**
21336 * @event ol.render.Event#render
21337 * @api
21338 */
21339 RENDER: 'render'
21340};
21341
21342goog.provide('ol.layer.Layer');
21343
21344goog.require('ol.events');
21345goog.require('ol.events.EventType');
21346goog.require('ol');
21347goog.require('ol.Object');
21348goog.require('ol.layer.Base');
21349goog.require('ol.layer.Property');
21350goog.require('ol.obj');
21351goog.require('ol.render.EventType');
21352goog.require('ol.source.State');
21353
21354
21355/**
21356 * @classdesc
21357 * Abstract base class; normally only used for creating subclasses and not
21358 * instantiated in apps.
21359 * A visual representation of raster or vector map data.
21360 * Layers group together those properties that pertain to how the data is to be
21361 * displayed, irrespective of the source of that data.
21362 *
21363 * Layers are usually added to a map with {@link ol.Map#addLayer}. Components
21364 * like {@link ol.interaction.Select} use unmanaged layers internally. These
21365 * unmanaged layers are associated with the map using
21366 * {@link ol.layer.Layer#setMap} instead.
21367 *
21368 * A generic `change` event is fired when the state of the source changes.
21369 *
21370 * @constructor
21371 * @abstract
21372 * @extends {ol.layer.Base}
21373 * @fires ol.render.Event
21374 * @param {olx.layer.LayerOptions} options Layer options.
21375 * @api
21376 */
21377ol.layer.Layer = function(options) {
21378
21379 var baseOptions = ol.obj.assign({}, options);
21380 delete baseOptions.source;
21381
21382 ol.layer.Base.call(this, /** @type {olx.layer.BaseOptions} */ (baseOptions));
21383
21384 /**
21385 * @private
21386 * @type {?ol.EventsKey}
21387 */
21388 this.mapPrecomposeKey_ = null;
21389
21390 /**
21391 * @private
21392 * @type {?ol.EventsKey}
21393 */
21394 this.mapRenderKey_ = null;
21395
21396 /**
21397 * @private
21398 * @type {?ol.EventsKey}
21399 */
21400 this.sourceChangeKey_ = null;
21401
21402 if (options.map) {
21403 this.setMap(options.map);
21404 }
21405
21406 ol.events.listen(this,
21407 ol.Object.getChangeEventType(ol.layer.Property.SOURCE),
21408 this.handleSourcePropertyChange_, this);
21409
21410 var source = options.source ? options.source : null;
21411 this.setSource(source);
21412};
21413ol.inherits(ol.layer.Layer, ol.layer.Base);
21414
21415
21416/**
21417 * Return `true` if the layer is visible, and if the passed resolution is
21418 * between the layer's minResolution and maxResolution. The comparison is
21419 * inclusive for `minResolution` and exclusive for `maxResolution`.
21420 * @param {ol.LayerState} layerState Layer state.
21421 * @param {number} resolution Resolution.
21422 * @return {boolean} The layer is visible at the given resolution.
21423 */
21424ol.layer.Layer.visibleAtResolution = function(layerState, resolution) {
21425 return layerState.visible && resolution >= layerState.minResolution &&
21426 resolution < layerState.maxResolution;
21427};
21428
21429
21430/**
21431 * @inheritDoc
21432 */
21433ol.layer.Layer.prototype.getLayersArray = function(opt_array) {
21434 var array = opt_array ? opt_array : [];
21435 array.push(this);
21436 return array;
21437};
21438
21439
21440/**
21441 * @inheritDoc
21442 */
21443ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) {
21444 var states = opt_states ? opt_states : [];
21445 states.push(this.getLayerState());
21446 return states;
21447};
21448
21449
21450/**
21451 * Get the layer source.
21452 * @return {ol.source.Source} The layer source (or `null` if not yet set).
21453 * @observable
21454 * @api
21455 */
21456ol.layer.Layer.prototype.getSource = function() {
21457 var source = this.get(ol.layer.Property.SOURCE);
21458 return /** @type {ol.source.Source} */ (source) || null;
21459};
21460
21461
21462/**
21463 * @inheritDoc
21464 */
21465ol.layer.Layer.prototype.getSourceState = function() {
21466 var source = this.getSource();
21467 return !source ? ol.source.State.UNDEFINED : source.getState();
21468};
21469
21470
21471/**
21472 * @private
21473 */
21474ol.layer.Layer.prototype.handleSourceChange_ = function() {
21475 this.changed();
21476};
21477
21478
21479/**
21480 * @private
21481 */
21482ol.layer.Layer.prototype.handleSourcePropertyChange_ = function() {
21483 if (this.sourceChangeKey_) {
21484 ol.events.unlistenByKey(this.sourceChangeKey_);
21485 this.sourceChangeKey_ = null;
21486 }
21487 var source = this.getSource();
21488 if (source) {
21489 this.sourceChangeKey_ = ol.events.listen(source,
21490 ol.events.EventType.CHANGE, this.handleSourceChange_, this);
21491 }
21492 this.changed();
21493};
21494
21495
21496/**
21497 * Sets the layer to be rendered on top of other layers on a map. The map will
21498 * not manage this layer in its layers collection, and the callback in
21499 * {@link ol.Map#forEachLayerAtPixel} will receive `null` as layer. This
21500 * is useful for temporary layers. To remove an unmanaged layer from the map,
21501 * use `#setMap(null)`.
21502 *
21503 * To add the layer to a map and have it managed by the map, use
21504 * {@link ol.Map#addLayer} instead.
21505 * @param {ol.Map} map Map.
21506 * @api
21507 */
21508ol.layer.Layer.prototype.setMap = function(map) {
21509 if (this.mapPrecomposeKey_) {
21510 ol.events.unlistenByKey(this.mapPrecomposeKey_);
21511 this.mapPrecomposeKey_ = null;
21512 }
21513 if (!map) {
21514 this.changed();
21515 }
21516 if (this.mapRenderKey_) {
21517 ol.events.unlistenByKey(this.mapRenderKey_);
21518 this.mapRenderKey_ = null;
21519 }
21520 if (map) {
21521 this.mapPrecomposeKey_ = ol.events.listen(
21522 map, ol.render.EventType.PRECOMPOSE, function(evt) {
21523 var layerState = this.getLayerState();
21524 layerState.managed = false;
21525 layerState.zIndex = Infinity;
21526 evt.frameState.layerStatesArray.push(layerState);
21527 evt.frameState.layerStates[ol.getUid(this)] = layerState;
21528 }, this);
21529 this.mapRenderKey_ = ol.events.listen(
21530 this, ol.events.EventType.CHANGE, map.render, map);
21531 this.changed();
21532 }
21533};
21534
21535
21536/**
21537 * Set the layer source.
21538 * @param {ol.source.Source} source The layer source.
21539 * @observable
21540 * @api
21541 */
21542ol.layer.Layer.prototype.setSource = function(source) {
21543 this.set(ol.layer.Property.SOURCE, source);
21544};
21545
21546goog.provide('ol.style.IconImageCache');
21547
21548goog.require('ol.color');
21549
21550
21551/**
21552 * @constructor
21553 */
21554ol.style.IconImageCache = function() {
21555
21556 /**
21557 * @type {Object.<string, ol.style.IconImage>}
21558 * @private
21559 */
21560 this.cache_ = {};
21561
21562 /**
21563 * @type {number}
21564 * @private
21565 */
21566 this.cacheSize_ = 0;
21567
21568 /**
21569 * @const
21570 * @type {number}
21571 * @private
21572 */
21573 this.maxCacheSize_ = 32;
21574};
21575
21576
21577/**
21578 * @param {string} src Src.
21579 * @param {?string} crossOrigin Cross origin.
21580 * @param {ol.Color} color Color.
21581 * @return {string} Cache key.
21582 */
21583ol.style.IconImageCache.getKey = function(src, crossOrigin, color) {
21584 var colorString = color ? ol.color.asString(color) : 'null';
21585 return crossOrigin + ':' + src + ':' + colorString;
21586};
21587
21588
21589/**
21590 * FIXME empty description for jsdoc
21591 */
21592ol.style.IconImageCache.prototype.clear = function() {
21593 this.cache_ = {};
21594 this.cacheSize_ = 0;
21595};
21596
21597
21598/**
21599 * FIXME empty description for jsdoc
21600 */
21601ol.style.IconImageCache.prototype.expire = function() {
21602 if (this.cacheSize_ > this.maxCacheSize_) {
21603 var i = 0;
21604 var key, iconImage;
21605 for (key in this.cache_) {
21606 iconImage = this.cache_[key];
21607 if ((i++ & 3) === 0 && !iconImage.hasListener()) {
21608 delete this.cache_[key];
21609 --this.cacheSize_;
21610 }
21611 }
21612 }
21613};
21614
21615
21616/**
21617 * @param {string} src Src.
21618 * @param {?string} crossOrigin Cross origin.
21619 * @param {ol.Color} color Color.
21620 * @return {ol.style.IconImage} Icon image.
21621 */
21622ol.style.IconImageCache.prototype.get = function(src, crossOrigin, color) {
21623 var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);
21624 return key in this.cache_ ? this.cache_[key] : null;
21625};
21626
21627
21628/**
21629 * @param {string} src Src.
21630 * @param {?string} crossOrigin Cross origin.
21631 * @param {ol.Color} color Color.
21632 * @param {ol.style.IconImage} iconImage Icon image.
21633 */
21634ol.style.IconImageCache.prototype.set = function(src, crossOrigin, color, iconImage) {
21635 var key = ol.style.IconImageCache.getKey(src, crossOrigin, color);
21636 this.cache_[key] = iconImage;
21637 ++this.cacheSize_;
21638};
21639
21640goog.provide('ol.style');
21641
21642goog.require('ol.style.IconImageCache');
21643
21644ol.style.iconImageCache = new ol.style.IconImageCache();
21645
21646goog.provide('ol.transform');
21647
21648goog.require('ol.asserts');
21649
21650
21651/**
21652 * Collection of affine 2d transformation functions. The functions work on an
21653 * array of 6 elements. The element order is compatible with the [SVGMatrix
21654 * interface](https://developer.mozilla.org/en-US/docs/Web/API/SVGMatrix) and is
21655 * a subset (elements a to f) of a 3x3 martrix:
21656 * ```
21657 * [ a c e ]
21658 * [ b d f ]
21659 * [ 0 0 1 ]
21660 * ```
21661 */
21662
21663
21664/**
21665 * @private
21666 * @type {ol.Transform}
21667 */
21668ol.transform.tmp_ = new Array(6);
21669
21670
21671/**
21672 * Create an identity transform.
21673 * @return {!ol.Transform} Identity transform.
21674 */
21675ol.transform.create = function() {
21676 return [1, 0, 0, 1, 0, 0];
21677};
21678
21679
21680/**
21681 * Resets the given transform to an identity transform.
21682 * @param {!ol.Transform} transform Transform.
21683 * @return {!ol.Transform} Transform.
21684 */
21685ol.transform.reset = function(transform) {
21686 return ol.transform.set(transform, 1, 0, 0, 1, 0, 0);
21687};
21688
21689
21690/**
21691 * Multiply the underlying matrices of two transforms and return the result in
21692 * the first transform.
21693 * @param {!ol.Transform} transform1 Transform parameters of matrix 1.
21694 * @param {!ol.Transform} transform2 Transform parameters of matrix 2.
21695 * @return {!ol.Transform} transform1 multiplied with transform2.
21696 */
21697ol.transform.multiply = function(transform1, transform2) {
21698 var a1 = transform1[0];
21699 var b1 = transform1[1];
21700 var c1 = transform1[2];
21701 var d1 = transform1[3];
21702 var e1 = transform1[4];
21703 var f1 = transform1[5];
21704 var a2 = transform2[0];
21705 var b2 = transform2[1];
21706 var c2 = transform2[2];
21707 var d2 = transform2[3];
21708 var e2 = transform2[4];
21709 var f2 = transform2[5];
21710
21711 transform1[0] = a1 * a2 + c1 * b2;
21712 transform1[1] = b1 * a2 + d1 * b2;
21713 transform1[2] = a1 * c2 + c1 * d2;
21714 transform1[3] = b1 * c2 + d1 * d2;
21715 transform1[4] = a1 * e2 + c1 * f2 + e1;
21716 transform1[5] = b1 * e2 + d1 * f2 + f1;
21717
21718 return transform1;
21719};
21720
21721/**
21722 * Set the transform components a-f on a given transform.
21723 * @param {!ol.Transform} transform Transform.
21724 * @param {number} a The a component of the transform.
21725 * @param {number} b The b component of the transform.
21726 * @param {number} c The c component of the transform.
21727 * @param {number} d The d component of the transform.
21728 * @param {number} e The e component of the transform.
21729 * @param {number} f The f component of the transform.
21730 * @return {!ol.Transform} Matrix with transform applied.
21731 */
21732ol.transform.set = function(transform, a, b, c, d, e, f) {
21733 transform[0] = a;
21734 transform[1] = b;
21735 transform[2] = c;
21736 transform[3] = d;
21737 transform[4] = e;
21738 transform[5] = f;
21739 return transform;
21740};
21741
21742
21743/**
21744 * Set transform on one matrix from another matrix.
21745 * @param {!ol.Transform} transform1 Matrix to set transform to.
21746 * @param {!ol.Transform} transform2 Matrix to set transform from.
21747 * @return {!ol.Transform} transform1 with transform from transform2 applied.
21748 */
21749ol.transform.setFromArray = function(transform1, transform2) {
21750 transform1[0] = transform2[0];
21751 transform1[1] = transform2[1];
21752 transform1[2] = transform2[2];
21753 transform1[3] = transform2[3];
21754 transform1[4] = transform2[4];
21755 transform1[5] = transform2[5];
21756 return transform1;
21757};
21758
21759
21760/**
21761 * Transforms the given coordinate with the given transform returning the
21762 * resulting, transformed coordinate. The coordinate will be modified in-place.
21763 *
21764 * @param {ol.Transform} transform The transformation.
21765 * @param {ol.Coordinate|ol.Pixel} coordinate The coordinate to transform.
21766 * @return {ol.Coordinate|ol.Pixel} return coordinate so that operations can be
21767 * chained together.
21768 */
21769ol.transform.apply = function(transform, coordinate) {
21770 var x = coordinate[0], y = coordinate[1];
21771 coordinate[0] = transform[0] * x + transform[2] * y + transform[4];
21772 coordinate[1] = transform[1] * x + transform[3] * y + transform[5];
21773 return coordinate;
21774};
21775
21776
21777/**
21778 * Applies rotation to the given transform.
21779 * @param {!ol.Transform} transform Transform.
21780 * @param {number} angle Angle in radians.
21781 * @return {!ol.Transform} The rotated transform.
21782 */
21783ol.transform.rotate = function(transform, angle) {
21784 var cos = Math.cos(angle);
21785 var sin = Math.sin(angle);
21786 return ol.transform.multiply(transform,
21787 ol.transform.set(ol.transform.tmp_, cos, sin, -sin, cos, 0, 0));
21788};
21789
21790
21791/**
21792 * Applies scale to a given transform.
21793 * @param {!ol.Transform} transform Transform.
21794 * @param {number} x Scale factor x.
21795 * @param {number} y Scale factor y.
21796 * @return {!ol.Transform} The scaled transform.
21797 */
21798ol.transform.scale = function(transform, x, y) {
21799 return ol.transform.multiply(transform,
21800 ol.transform.set(ol.transform.tmp_, x, 0, 0, y, 0, 0));
21801};
21802
21803
21804/**
21805 * Applies translation to the given transform.
21806 * @param {!ol.Transform} transform Transform.
21807 * @param {number} dx Translation x.
21808 * @param {number} dy Translation y.
21809 * @return {!ol.Transform} The translated transform.
21810 */
21811ol.transform.translate = function(transform, dx, dy) {
21812 return ol.transform.multiply(transform,
21813 ol.transform.set(ol.transform.tmp_, 1, 0, 0, 1, dx, dy));
21814};
21815
21816
21817/**
21818 * Creates a composite transform given an initial translation, scale, rotation, and
21819 * final translation (in that order only, not commutative).
21820 * @param {!ol.Transform} transform The transform (will be modified in place).
21821 * @param {number} dx1 Initial translation x.
21822 * @param {number} dy1 Initial translation y.
21823 * @param {number} sx Scale factor x.
21824 * @param {number} sy Scale factor y.
21825 * @param {number} angle Rotation (in counter-clockwise radians).
21826 * @param {number} dx2 Final translation x.
21827 * @param {number} dy2 Final translation y.
21828 * @return {!ol.Transform} The composite transform.
21829 */
21830ol.transform.compose = function(transform, dx1, dy1, sx, sy, angle, dx2, dy2) {
21831 var sin = Math.sin(angle);
21832 var cos = Math.cos(angle);
21833 transform[0] = sx * cos;
21834 transform[1] = sy * sin;
21835 transform[2] = -sx * sin;
21836 transform[3] = sy * cos;
21837 transform[4] = dx2 * sx * cos - dy2 * sx * sin + dx1;
21838 transform[5] = dx2 * sy * sin + dy2 * sy * cos + dy1;
21839 return transform;
21840};
21841
21842
21843/**
21844 * Invert the given transform.
21845 * @param {!ol.Transform} transform Transform.
21846 * @return {!ol.Transform} Inverse of the transform.
21847 */
21848ol.transform.invert = function(transform) {
21849 var det = ol.transform.determinant(transform);
21850 ol.asserts.assert(det !== 0, 32); // Transformation matrix cannot be inverted
21851
21852 var a = transform[0];
21853 var b = transform[1];
21854 var c = transform[2];
21855 var d = transform[3];
21856 var e = transform[4];
21857 var f = transform[5];
21858
21859 transform[0] = d / det;
21860 transform[1] = -b / det;
21861 transform[2] = -c / det;
21862 transform[3] = a / det;
21863 transform[4] = (c * f - d * e) / det;
21864 transform[5] = -(a * f - b * e) / det;
21865
21866 return transform;
21867};
21868
21869
21870/**
21871 * Returns the determinant of the given matrix.
21872 * @param {!ol.Transform} mat Matrix.
21873 * @return {number} Determinant.
21874 */
21875ol.transform.determinant = function(mat) {
21876 return mat[0] * mat[3] - mat[1] * mat[2];
21877};
21878
21879goog.provide('ol.renderer.Map');
21880
21881goog.require('ol');
21882goog.require('ol.Disposable');
21883goog.require('ol.events');
21884goog.require('ol.events.EventType');
21885goog.require('ol.extent');
21886goog.require('ol.functions');
21887goog.require('ol.layer.Layer');
21888goog.require('ol.style');
21889goog.require('ol.transform');
21890
21891
21892/**
21893 * @constructor
21894 * @abstract
21895 * @extends {ol.Disposable}
21896 * @param {Element} container Container.
21897 * @param {ol.Map} map Map.
21898 * @struct
21899 */
21900ol.renderer.Map = function(container, map) {
21901
21902 ol.Disposable.call(this);
21903
21904
21905 /**
21906 * @private
21907 * @type {ol.Map}
21908 */
21909 this.map_ = map;
21910
21911 /**
21912 * @private
21913 * @type {Object.<string, ol.renderer.Layer>}
21914 */
21915 this.layerRenderers_ = {};
21916
21917 /**
21918 * @private
21919 * @type {Object.<string, ol.EventsKey>}
21920 */
21921 this.layerRendererListeners_ = {};
21922
21923};
21924ol.inherits(ol.renderer.Map, ol.Disposable);
21925
21926
21927/**
21928 * @param {olx.FrameState} frameState FrameState.
21929 * @protected
21930 */
21931ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) {
21932 var viewState = frameState.viewState;
21933 var coordinateToPixelTransform = frameState.coordinateToPixelTransform;
21934 var pixelToCoordinateTransform = frameState.pixelToCoordinateTransform;
21935
21936 ol.transform.compose(coordinateToPixelTransform,
21937 frameState.size[0] / 2, frameState.size[1] / 2,
21938 1 / viewState.resolution, -1 / viewState.resolution,
21939 -viewState.rotation,
21940 -viewState.center[0], -viewState.center[1]);
21941
21942 ol.transform.invert(
21943 ol.transform.setFromArray(pixelToCoordinateTransform, coordinateToPixelTransform));
21944};
21945
21946
21947/**
21948 * @inheritDoc
21949 */
21950ol.renderer.Map.prototype.disposeInternal = function() {
21951 for (var id in this.layerRenderers_) {
21952 this.layerRenderers_[id].dispose();
21953 }
21954};
21955
21956
21957/**
21958 * @param {ol.Map} map Map.
21959 * @param {olx.FrameState} frameState Frame state.
21960 * @private
21961 */
21962ol.renderer.Map.expireIconCache_ = function(map, frameState) {
21963 var cache = ol.style.iconImageCache;
21964 cache.expire();
21965};
21966
21967
21968/**
21969 * @param {ol.Coordinate} coordinate Coordinate.
21970 * @param {olx.FrameState} frameState FrameState.
21971 * @param {number} hitTolerance Hit tolerance in pixels.
21972 * @param {function(this: S, (ol.Feature|ol.render.Feature),
21973 * ol.layer.Layer): T} callback Feature callback.
21974 * @param {S} thisArg Value to use as `this` when executing `callback`.
21975 * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
21976 * function, only layers which are visible and for which this function
21977 * returns `true` will be tested for features. By default, all visible
21978 * layers will be tested.
21979 * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.
21980 * @return {T|undefined} Callback result.
21981 * @template S,T,U
21982 */
21983ol.renderer.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg,
21984 layerFilter, thisArg2) {
21985 var result;
21986 var viewState = frameState.viewState;
21987 var viewResolution = viewState.resolution;
21988
21989 /**
21990 * @param {ol.Feature|ol.render.Feature} feature Feature.
21991 * @param {ol.layer.Layer} layer Layer.
21992 * @return {?} Callback result.
21993 */
21994 function forEachFeatureAtCoordinate(feature, layer) {
21995 var key = ol.getUid(feature).toString();
21996 var managed = frameState.layerStates[ol.getUid(layer)].managed;
21997 if (!(key in frameState.skippedFeatureUids && !managed)) {
21998 return callback.call(thisArg, feature, managed ? layer : null);
21999 }
22000 }
22001
22002 var projection = viewState.projection;
22003
22004 var translatedCoordinate = coordinate;
22005 if (projection.canWrapX()) {
22006 var projectionExtent = projection.getExtent();
22007 var worldWidth = ol.extent.getWidth(projectionExtent);
22008 var x = coordinate[0];
22009 if (x < projectionExtent[0] || x > projectionExtent[2]) {
22010 var worldsAway = Math.ceil((projectionExtent[0] - x) / worldWidth);
22011 translatedCoordinate = [x + worldWidth * worldsAway, coordinate[1]];
22012 }
22013 }
22014
22015 var layerStates = frameState.layerStatesArray;
22016 var numLayers = layerStates.length;
22017 var i;
22018 for (i = numLayers - 1; i >= 0; --i) {
22019 var layerState = layerStates[i];
22020 var layer = layerState.layer;
22021 if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
22022 layerFilter.call(thisArg2, layer)) {
22023 var layerRenderer = this.getLayerRenderer(layer);
22024 if (layer.getSource()) {
22025 result = layerRenderer.forEachFeatureAtCoordinate(
22026 layer.getSource().getWrapX() ? translatedCoordinate : coordinate,
22027 frameState, hitTolerance, forEachFeatureAtCoordinate, thisArg);
22028 }
22029 if (result) {
22030 return result;
22031 }
22032 }
22033 }
22034 return undefined;
22035};
22036
22037
22038/**
22039 * @abstract
22040 * @param {ol.Pixel} pixel Pixel.
22041 * @param {olx.FrameState} frameState FrameState.
22042 * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
22043 * callback.
22044 * @param {S} thisArg Value to use as `this` when executing `callback`.
22045 * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
22046 * function, only layers which are visible and for which this function
22047 * returns `true` will be tested for features. By default, all visible
22048 * layers will be tested.
22049 * @param {U} thisArg2 Value to use as `this` when executing `layerFilter`.
22050 * @return {T|undefined} Callback result.
22051 * @template S,T,U
22052 */
22053ol.renderer.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
22054 layerFilter, thisArg2) {};
22055
22056
22057/**
22058 * @param {ol.Coordinate} coordinate Coordinate.
22059 * @param {olx.FrameState} frameState FrameState.
22060 * @param {number} hitTolerance Hit tolerance in pixels.
22061 * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter
22062 * function, only layers which are visible and for which this function
22063 * returns `true` will be tested for features. By default, all visible
22064 * layers will be tested.
22065 * @param {U} thisArg Value to use as `this` when executing `layerFilter`.
22066 * @return {boolean} Is there a feature at the given coordinate?
22067 * @template U
22068 */
22069ol.renderer.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, layerFilter, thisArg) {
22070 var hasFeature = this.forEachFeatureAtCoordinate(
22071 coordinate, frameState, hitTolerance, ol.functions.TRUE, this, layerFilter, thisArg);
22072
22073 return hasFeature !== undefined;
22074};
22075
22076
22077/**
22078 * @param {ol.layer.Layer} layer Layer.
22079 * @protected
22080 * @return {ol.renderer.Layer} Layer renderer.
22081 */
22082ol.renderer.Map.prototype.getLayerRenderer = function(layer) {
22083 var layerKey = ol.getUid(layer).toString();
22084 if (layerKey in this.layerRenderers_) {
22085 return this.layerRenderers_[layerKey];
22086 } else {
22087 var layerRenderer = layer.createRenderer(this);
22088 this.layerRenderers_[layerKey] = layerRenderer;
22089 this.layerRendererListeners_[layerKey] = ol.events.listen(layerRenderer,
22090 ol.events.EventType.CHANGE, this.handleLayerRendererChange_, this);
22091
22092 return layerRenderer;
22093 }
22094};
22095
22096
22097/**
22098 * @param {string} layerKey Layer key.
22099 * @protected
22100 * @return {ol.renderer.Layer} Layer renderer.
22101 */
22102ol.renderer.Map.prototype.getLayerRendererByKey = function(layerKey) {
22103 return this.layerRenderers_[layerKey];
22104};
22105
22106
22107/**
22108 * @protected
22109 * @return {Object.<string, ol.renderer.Layer>} Layer renderers.
22110 */
22111ol.renderer.Map.prototype.getLayerRenderers = function() {
22112 return this.layerRenderers_;
22113};
22114
22115
22116/**
22117 * @return {ol.Map} Map.
22118 */
22119ol.renderer.Map.prototype.getMap = function() {
22120 return this.map_;
22121};
22122
22123
22124/**
22125 * @abstract
22126 * @return {string} Type
22127 */
22128ol.renderer.Map.prototype.getType = function() {};
22129
22130
22131/**
22132 * Handle changes in a layer renderer.
22133 * @private
22134 */
22135ol.renderer.Map.prototype.handleLayerRendererChange_ = function() {
22136 this.map_.render();
22137};
22138
22139
22140/**
22141 * @param {string} layerKey Layer key.
22142 * @return {ol.renderer.Layer} Layer renderer.
22143 * @private
22144 */
22145ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) {
22146 var layerRenderer = this.layerRenderers_[layerKey];
22147 delete this.layerRenderers_[layerKey];
22148
22149 ol.events.unlistenByKey(this.layerRendererListeners_[layerKey]);
22150 delete this.layerRendererListeners_[layerKey];
22151
22152 return layerRenderer;
22153};
22154
22155
22156/**
22157 * Render.
22158 * @param {?olx.FrameState} frameState Frame state.
22159 */
22160ol.renderer.Map.prototype.renderFrame = ol.nullFunction;
22161
22162
22163/**
22164 * @param {ol.Map} map Map.
22165 * @param {olx.FrameState} frameState Frame state.
22166 * @private
22167 */
22168ol.renderer.Map.prototype.removeUnusedLayerRenderers_ = function(map, frameState) {
22169 var layerKey;
22170 for (layerKey in this.layerRenderers_) {
22171 if (!frameState || !(layerKey in frameState.layerStates)) {
22172 this.removeLayerRendererByKey_(layerKey).dispose();
22173 }
22174 }
22175};
22176
22177
22178/**
22179 * @param {olx.FrameState} frameState Frame state.
22180 * @protected
22181 */
22182ol.renderer.Map.prototype.scheduleExpireIconCache = function(frameState) {
22183 frameState.postRenderFunctions.push(
22184 /** @type {ol.PostRenderFunction} */ (ol.renderer.Map.expireIconCache_)
22185 );
22186};
22187
22188
22189/**
22190 * @param {!olx.FrameState} frameState Frame state.
22191 * @protected
22192 */
22193ol.renderer.Map.prototype.scheduleRemoveUnusedLayerRenderers = function(frameState) {
22194 var layerKey;
22195 for (layerKey in this.layerRenderers_) {
22196 if (!(layerKey in frameState.layerStates)) {
22197 frameState.postRenderFunctions.push(
22198 /** @type {ol.PostRenderFunction} */ (this.removeUnusedLayerRenderers_.bind(this))
22199 );
22200 return;
22201 }
22202 }
22203};
22204
22205
22206/**
22207 * @param {ol.LayerState} state1 First layer state.
22208 * @param {ol.LayerState} state2 Second layer state.
22209 * @return {number} The zIndex difference.
22210 */
22211ol.renderer.Map.sortByZIndex = function(state1, state2) {
22212 return state1.zIndex - state2.zIndex;
22213};
22214
22215goog.provide('ol.renderer.Type');
22216
22217
22218/**
22219 * Available renderers: `'canvas'` or `'webgl'`.
22220 * @enum {string}
22221 */
22222ol.renderer.Type = {
22223 CANVAS: 'canvas',
22224 WEBGL: 'webgl'
22225};
22226
22227goog.provide('ol.render.Event');
22228
22229goog.require('ol');
22230goog.require('ol.events.Event');
22231
22232
22233/**
22234 * @constructor
22235 * @extends {ol.events.Event}
22236 * @implements {oli.render.Event}
22237 * @param {ol.render.EventType} type Type.
22238 * @param {ol.render.VectorContext=} opt_vectorContext Vector context.
22239 * @param {olx.FrameState=} opt_frameState Frame state.
22240 * @param {?CanvasRenderingContext2D=} opt_context Context.
22241 * @param {?ol.webgl.Context=} opt_glContext WebGL Context.
22242 */
22243ol.render.Event = function(
22244 type, opt_vectorContext, opt_frameState, opt_context,
22245 opt_glContext) {
22246
22247 ol.events.Event.call(this, type);
22248
22249 /**
22250 * For canvas, this is an instance of {@link ol.render.canvas.Immediate}.
22251 * @type {ol.render.VectorContext|undefined}
22252 * @api
22253 */
22254 this.vectorContext = opt_vectorContext;
22255
22256 /**
22257 * An object representing the current render frame state.
22258 * @type {olx.FrameState|undefined}
22259 * @api
22260 */
22261 this.frameState = opt_frameState;
22262
22263 /**
22264 * Canvas context. Only available when a Canvas renderer is used, null
22265 * otherwise.
22266 * @type {CanvasRenderingContext2D|null|undefined}
22267 * @api
22268 */
22269 this.context = opt_context;
22270
22271 /**
22272 * WebGL context. Only available when a WebGL renderer is used, null
22273 * otherwise.
22274 * @type {ol.webgl.Context|null|undefined}
22275 * @api
22276 */
22277 this.glContext = opt_glContext;
22278
22279};
22280ol.inherits(ol.render.Event, ol.events.Event);
22281
22282goog.provide('ol.render.canvas');
22283
22284
22285/**
22286 * @const
22287 * @type {string}
22288 */
22289ol.render.canvas.defaultFont = '10px sans-serif';
22290
22291
22292/**
22293 * @const
22294 * @type {ol.Color}
22295 */
22296ol.render.canvas.defaultFillStyle = [0, 0, 0, 1];
22297
22298
22299/**
22300 * @const
22301 * @type {string}
22302 */
22303ol.render.canvas.defaultLineCap = 'round';
22304
22305
22306/**
22307 * @const
22308 * @type {Array.<number>}
22309 */
22310ol.render.canvas.defaultLineDash = [];
22311
22312
22313/**
22314 * @const
22315 * @type {number}
22316 */
22317ol.render.canvas.defaultLineDashOffset = 0;
22318
22319
22320/**
22321 * @const
22322 * @type {string}
22323 */
22324ol.render.canvas.defaultLineJoin = 'round';
22325
22326
22327/**
22328 * @const
22329 * @type {number}
22330 */
22331ol.render.canvas.defaultMiterLimit = 10;
22332
22333
22334/**
22335 * @const
22336 * @type {ol.Color}
22337 */
22338ol.render.canvas.defaultStrokeStyle = [0, 0, 0, 1];
22339
22340
22341/**
22342 * @const
22343 * @type {string}
22344 */
22345ol.render.canvas.defaultTextAlign = 'center';
22346
22347
22348/**
22349 * @const
22350 * @type {string}
22351 */
22352ol.render.canvas.defaultTextBaseline = 'middle';
22353
22354
22355/**
22356 * @const
22357 * @type {number}
22358 */
22359ol.render.canvas.defaultLineWidth = 1;
22360
22361
22362/**
22363 * @param {CanvasRenderingContext2D} context Context.
22364 * @param {number} rotation Rotation.
22365 * @param {number} offsetX X offset.
22366 * @param {number} offsetY Y offset.
22367 */
22368ol.render.canvas.rotateAtOffset = function(context, rotation, offsetX, offsetY) {
22369 if (rotation !== 0) {
22370 context.translate(offsetX, offsetY);
22371 context.rotate(rotation);
22372 context.translate(-offsetX, -offsetY);
22373 }
22374};
22375
22376goog.provide('ol.render.VectorContext');
22377
22378
22379/**
22380 * Context for drawing geometries. A vector context is available on render
22381 * events and does not need to be constructed directly.
22382 * @constructor
22383 * @abstract
22384 * @struct
22385 * @api
22386 */
22387ol.render.VectorContext = function() {
22388};
22389
22390
22391/**
22392 * Render a geometry with a custom renderer.
22393 *
22394 * @param {ol.geom.SimpleGeometry} geometry Geometry.
22395 * @param {ol.Feature|ol.render.Feature} feature Feature.
22396 * @param {Function} renderer Renderer.
22397 */
22398ol.render.VectorContext.prototype.drawCustom = function(geometry, feature, renderer) {};
22399
22400
22401/**
22402 * Render a geometry.
22403 *
22404 * @param {ol.geom.Geometry} geometry The geometry to render.
22405 */
22406ol.render.VectorContext.prototype.drawGeometry = function(geometry) {};
22407
22408
22409/**
22410 * Set the rendering style.
22411 *
22412 * @param {ol.style.Style} style The rendering style.
22413 */
22414ol.render.VectorContext.prototype.setStyle = function(style) {};
22415
22416
22417/**
22418 * @param {ol.geom.Circle} circleGeometry Circle geometry.
22419 * @param {ol.Feature} feature Feature.
22420 */
22421ol.render.VectorContext.prototype.drawCircle = function(circleGeometry, feature) {};
22422
22423
22424/**
22425 * @param {ol.Feature} feature Feature.
22426 * @param {ol.style.Style} style Style.
22427 */
22428ol.render.VectorContext.prototype.drawFeature = function(feature, style) {};
22429
22430
22431/**
22432 * @param {ol.geom.GeometryCollection} geometryCollectionGeometry Geometry
22433 * collection.
22434 * @param {ol.Feature} feature Feature.
22435 */
22436ol.render.VectorContext.prototype.drawGeometryCollection = function(geometryCollectionGeometry, feature) {};
22437
22438
22439/**
22440 * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line
22441 * string geometry.
22442 * @param {ol.Feature|ol.render.Feature} feature Feature.
22443 */
22444ol.render.VectorContext.prototype.drawLineString = function(lineStringGeometry, feature) {};
22445
22446
22447/**
22448 * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry
22449 * MultiLineString geometry.
22450 * @param {ol.Feature|ol.render.Feature} feature Feature.
22451 */
22452ol.render.VectorContext.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {};
22453
22454
22455/**
22456 * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint
22457 * geometry.
22458 * @param {ol.Feature|ol.render.Feature} feature Feature.
22459 */
22460ol.render.VectorContext.prototype.drawMultiPoint = function(multiPointGeometry, feature) {};
22461
22462
22463/**
22464 * @param {ol.geom.MultiPolygon} multiPolygonGeometry MultiPolygon geometry.
22465 * @param {ol.Feature|ol.render.Feature} feature Feature.
22466 */
22467ol.render.VectorContext.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {};
22468
22469
22470/**
22471 * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry.
22472 * @param {ol.Feature|ol.render.Feature} feature Feature.
22473 */
22474ol.render.VectorContext.prototype.drawPoint = function(pointGeometry, feature) {};
22475
22476
22477/**
22478 * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon
22479 * geometry.
22480 * @param {ol.Feature|ol.render.Feature} feature Feature.
22481 */
22482ol.render.VectorContext.prototype.drawPolygon = function(polygonGeometry, feature) {};
22483
22484
22485/**
22486 * @param {Array.<number>} flatCoordinates Flat coordinates.
22487 * @param {number} offset Offset.
22488 * @param {number} end End.
22489 * @param {number} stride Stride.
22490 * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
22491 * @param {ol.Feature|ol.render.Feature} feature Feature.
22492 */
22493ol.render.VectorContext.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {};
22494
22495
22496/**
22497 * @param {ol.style.Fill} fillStyle Fill style.
22498 * @param {ol.style.Stroke} strokeStyle Stroke style.
22499 */
22500ol.render.VectorContext.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {};
22501
22502
22503/**
22504 * @param {ol.style.Image} imageStyle Image style.
22505 */
22506ol.render.VectorContext.prototype.setImageStyle = function(imageStyle) {};
22507
22508
22509/**
22510 * @param {ol.style.Text} textStyle Text style.
22511 */
22512ol.render.VectorContext.prototype.setTextStyle = function(textStyle) {};
22513
22514// FIXME test, especially polygons with holes and multipolygons
22515// FIXME need to handle large thick features (where pixel size matters)
22516// FIXME add offset and end to ol.geom.flat.transform.transform2D?
22517
22518goog.provide('ol.render.canvas.Immediate');
22519
22520goog.require('ol');
22521goog.require('ol.array');
22522goog.require('ol.colorlike');
22523goog.require('ol.extent');
22524goog.require('ol.geom.GeometryType');
22525goog.require('ol.geom.SimpleGeometry');
22526goog.require('ol.geom.flat.transform');
22527goog.require('ol.has');
22528goog.require('ol.render.VectorContext');
22529goog.require('ol.render.canvas');
22530goog.require('ol.transform');
22531
22532
22533/**
22534 * @classdesc
22535 * A concrete subclass of {@link ol.render.VectorContext} that implements
22536 * direct rendering of features and geometries to an HTML5 Canvas context.
22537 * Instances of this class are created internally by the library and
22538 * provided to application code as vectorContext member of the
22539 * {@link ol.render.Event} object associated with postcompose, precompose and
22540 * render events emitted by layers and maps.
22541 *
22542 * @constructor
22543 * @extends {ol.render.VectorContext}
22544 * @param {CanvasRenderingContext2D} context Context.
22545 * @param {number} pixelRatio Pixel ratio.
22546 * @param {ol.Extent} extent Extent.
22547 * @param {ol.Transform} transform Transform.
22548 * @param {number} viewRotation View rotation.
22549 * @struct
22550 */
22551ol.render.canvas.Immediate = function(context, pixelRatio, extent, transform, viewRotation) {
22552 ol.render.VectorContext.call(this);
22553
22554 /**
22555 * @private
22556 * @type {CanvasRenderingContext2D}
22557 */
22558 this.context_ = context;
22559
22560 /**
22561 * @private
22562 * @type {number}
22563 */
22564 this.pixelRatio_ = pixelRatio;
22565
22566 /**
22567 * @private
22568 * @type {ol.Extent}
22569 */
22570 this.extent_ = extent;
22571
22572 /**
22573 * @private
22574 * @type {ol.Transform}
22575 */
22576 this.transform_ = transform;
22577
22578 /**
22579 * @private
22580 * @type {number}
22581 */
22582 this.viewRotation_ = viewRotation;
22583
22584 /**
22585 * @private
22586 * @type {?ol.CanvasFillState}
22587 */
22588 this.contextFillState_ = null;
22589
22590 /**
22591 * @private
22592 * @type {?ol.CanvasStrokeState}
22593 */
22594 this.contextStrokeState_ = null;
22595
22596 /**
22597 * @private
22598 * @type {?ol.CanvasTextState}
22599 */
22600 this.contextTextState_ = null;
22601
22602 /**
22603 * @private
22604 * @type {?ol.CanvasFillState}
22605 */
22606 this.fillState_ = null;
22607
22608 /**
22609 * @private
22610 * @type {?ol.CanvasStrokeState}
22611 */
22612 this.strokeState_ = null;
22613
22614 /**
22615 * @private
22616 * @type {HTMLCanvasElement|HTMLVideoElement|Image}
22617 */
22618 this.image_ = null;
22619
22620 /**
22621 * @private
22622 * @type {number}
22623 */
22624 this.imageAnchorX_ = 0;
22625
22626 /**
22627 * @private
22628 * @type {number}
22629 */
22630 this.imageAnchorY_ = 0;
22631
22632 /**
22633 * @private
22634 * @type {number}
22635 */
22636 this.imageHeight_ = 0;
22637
22638 /**
22639 * @private
22640 * @type {number}
22641 */
22642 this.imageOpacity_ = 0;
22643
22644 /**
22645 * @private
22646 * @type {number}
22647 */
22648 this.imageOriginX_ = 0;
22649
22650 /**
22651 * @private
22652 * @type {number}
22653 */
22654 this.imageOriginY_ = 0;
22655
22656 /**
22657 * @private
22658 * @type {boolean}
22659 */
22660 this.imageRotateWithView_ = false;
22661
22662 /**
22663 * @private
22664 * @type {number}
22665 */
22666 this.imageRotation_ = 0;
22667
22668 /**
22669 * @private
22670 * @type {number}
22671 */
22672 this.imageScale_ = 0;
22673
22674 /**
22675 * @private
22676 * @type {boolean}
22677 */
22678 this.imageSnapToPixel_ = false;
22679
22680 /**
22681 * @private
22682 * @type {number}
22683 */
22684 this.imageWidth_ = 0;
22685
22686 /**
22687 * @private
22688 * @type {string}
22689 */
22690 this.text_ = '';
22691
22692 /**
22693 * @private
22694 * @type {number}
22695 */
22696 this.textOffsetX_ = 0;
22697
22698 /**
22699 * @private
22700 * @type {number}
22701 */
22702 this.textOffsetY_ = 0;
22703
22704 /**
22705 * @private
22706 * @type {boolean}
22707 */
22708 this.textRotateWithView_ = false;
22709
22710 /**
22711 * @private
22712 * @type {number}
22713 */
22714 this.textRotation_ = 0;
22715
22716 /**
22717 * @private
22718 * @type {number}
22719 */
22720 this.textScale_ = 0;
22721
22722 /**
22723 * @private
22724 * @type {?ol.CanvasFillState}
22725 */
22726 this.textFillState_ = null;
22727
22728 /**
22729 * @private
22730 * @type {?ol.CanvasStrokeState}
22731 */
22732 this.textStrokeState_ = null;
22733
22734 /**
22735 * @private
22736 * @type {?ol.CanvasTextState}
22737 */
22738 this.textState_ = null;
22739
22740 /**
22741 * @private
22742 * @type {Array.<number>}
22743 */
22744 this.pixelCoordinates_ = [];
22745
22746 /**
22747 * @private
22748 * @type {ol.Transform}
22749 */
22750 this.tmpLocalTransform_ = ol.transform.create();
22751
22752};
22753ol.inherits(ol.render.canvas.Immediate, ol.render.VectorContext);
22754
22755
22756/**
22757 * @param {Array.<number>} flatCoordinates Flat coordinates.
22758 * @param {number} offset Offset.
22759 * @param {number} end End.
22760 * @param {number} stride Stride.
22761 * @private
22762 */
22763ol.render.canvas.Immediate.prototype.drawImages_ = function(flatCoordinates, offset, end, stride) {
22764 if (!this.image_) {
22765 return;
22766 }
22767 var pixelCoordinates = ol.geom.flat.transform.transform2D(
22768 flatCoordinates, offset, end, 2, this.transform_,
22769 this.pixelCoordinates_);
22770 var context = this.context_;
22771 var localTransform = this.tmpLocalTransform_;
22772 var alpha = context.globalAlpha;
22773 if (this.imageOpacity_ != 1) {
22774 context.globalAlpha = alpha * this.imageOpacity_;
22775 }
22776 var rotation = this.imageRotation_;
22777 if (this.imageRotateWithView_) {
22778 rotation += this.viewRotation_;
22779 }
22780 var i, ii;
22781 for (i = 0, ii = pixelCoordinates.length; i < ii; i += 2) {
22782 var x = pixelCoordinates[i] - this.imageAnchorX_;
22783 var y = pixelCoordinates[i + 1] - this.imageAnchorY_;
22784 if (this.imageSnapToPixel_) {
22785 x = Math.round(x);
22786 y = Math.round(y);
22787 }
22788 if (rotation !== 0 || this.imageScale_ != 1) {
22789 var centerX = x + this.imageAnchorX_;
22790 var centerY = y + this.imageAnchorY_;
22791 ol.transform.compose(localTransform,
22792 centerX, centerY,
22793 this.imageScale_, this.imageScale_,
22794 rotation,
22795 -centerX, -centerY);
22796 context.setTransform.apply(context, localTransform);
22797 }
22798 context.drawImage(this.image_, this.imageOriginX_, this.imageOriginY_,
22799 this.imageWidth_, this.imageHeight_, x, y,
22800 this.imageWidth_, this.imageHeight_);
22801 }
22802 if (rotation !== 0 || this.imageScale_ != 1) {
22803 context.setTransform(1, 0, 0, 1, 0, 0);
22804 }
22805 if (this.imageOpacity_ != 1) {
22806 context.globalAlpha = alpha;
22807 }
22808};
22809
22810
22811/**
22812 * @param {Array.<number>} flatCoordinates Flat coordinates.
22813 * @param {number} offset Offset.
22814 * @param {number} end End.
22815 * @param {number} stride Stride.
22816 * @private
22817 */
22818ol.render.canvas.Immediate.prototype.drawText_ = function(flatCoordinates, offset, end, stride) {
22819 if (!this.textState_ || this.text_ === '') {
22820 return;
22821 }
22822 if (this.textFillState_) {
22823 this.setContextFillState_(this.textFillState_);
22824 }
22825 if (this.textStrokeState_) {
22826 this.setContextStrokeState_(this.textStrokeState_);
22827 }
22828 this.setContextTextState_(this.textState_);
22829 var pixelCoordinates = ol.geom.flat.transform.transform2D(
22830 flatCoordinates, offset, end, stride, this.transform_,
22831 this.pixelCoordinates_);
22832 var context = this.context_;
22833 var rotation = this.textRotation_;
22834 if (this.textRotateWithView_) {
22835 rotation += this.viewRotation_;
22836 }
22837 for (; offset < end; offset += stride) {
22838 var x = pixelCoordinates[offset] + this.textOffsetX_;
22839 var y = pixelCoordinates[offset + 1] + this.textOffsetY_;
22840 if (rotation !== 0 || this.textScale_ != 1) {
22841 var localTransform = ol.transform.compose(this.tmpLocalTransform_,
22842 x, y,
22843 this.textScale_, this.textScale_,
22844 rotation,
22845 -x, -y);
22846 context.setTransform.apply(context, localTransform);
22847 }
22848 if (this.textStrokeState_) {
22849 context.strokeText(this.text_, x, y);
22850 }
22851 if (this.textFillState_) {
22852 context.fillText(this.text_, x, y);
22853 }
22854 }
22855 if (rotation !== 0 || this.textScale_ != 1) {
22856 context.setTransform(1, 0, 0, 1, 0, 0);
22857 }
22858};
22859
22860
22861/**
22862 * @param {Array.<number>} flatCoordinates Flat coordinates.
22863 * @param {number} offset Offset.
22864 * @param {number} end End.
22865 * @param {number} stride Stride.
22866 * @param {boolean} close Close.
22867 * @private
22868 * @return {number} end End.
22869 */
22870ol.render.canvas.Immediate.prototype.moveToLineTo_ = function(flatCoordinates, offset, end, stride, close) {
22871 var context = this.context_;
22872 var pixelCoordinates = ol.geom.flat.transform.transform2D(
22873 flatCoordinates, offset, end, stride, this.transform_,
22874 this.pixelCoordinates_);
22875 context.moveTo(pixelCoordinates[0], pixelCoordinates[1]);
22876 var length = pixelCoordinates.length;
22877 if (close) {
22878 length -= 2;
22879 }
22880 for (var i = 2; i < length; i += 2) {
22881 context.lineTo(pixelCoordinates[i], pixelCoordinates[i + 1]);
22882 }
22883 if (close) {
22884 context.closePath();
22885 }
22886 return end;
22887};
22888
22889
22890/**
22891 * @param {Array.<number>} flatCoordinates Flat coordinates.
22892 * @param {number} offset Offset.
22893 * @param {Array.<number>} ends Ends.
22894 * @param {number} stride Stride.
22895 * @private
22896 * @return {number} End.
22897 */
22898ol.render.canvas.Immediate.prototype.drawRings_ = function(flatCoordinates, offset, ends, stride) {
22899 var i, ii;
22900 for (i = 0, ii = ends.length; i < ii; ++i) {
22901 offset = this.moveToLineTo_(
22902 flatCoordinates, offset, ends[i], stride, true);
22903 }
22904 return offset;
22905};
22906
22907
22908/**
22909 * Render a circle geometry into the canvas. Rendering is immediate and uses
22910 * the current fill and stroke styles.
22911 *
22912 * @param {ol.geom.Circle} geometry Circle geometry.
22913 * @override
22914 * @api
22915 */
22916ol.render.canvas.Immediate.prototype.drawCircle = function(geometry) {
22917 if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
22918 return;
22919 }
22920 if (this.fillState_ || this.strokeState_) {
22921 if (this.fillState_) {
22922 this.setContextFillState_(this.fillState_);
22923 }
22924 if (this.strokeState_) {
22925 this.setContextStrokeState_(this.strokeState_);
22926 }
22927 var pixelCoordinates = ol.geom.SimpleGeometry.transform2D(
22928 geometry, this.transform_, this.pixelCoordinates_);
22929 var dx = pixelCoordinates[2] - pixelCoordinates[0];
22930 var dy = pixelCoordinates[3] - pixelCoordinates[1];
22931 var radius = Math.sqrt(dx * dx + dy * dy);
22932 var context = this.context_;
22933 context.beginPath();
22934 context.arc(
22935 pixelCoordinates[0], pixelCoordinates[1], radius, 0, 2 * Math.PI);
22936 if (this.fillState_) {
22937 context.fill();
22938 }
22939 if (this.strokeState_) {
22940 context.stroke();
22941 }
22942 }
22943 if (this.text_ !== '') {
22944 this.drawText_(geometry.getCenter(), 0, 2, 2);
22945 }
22946};
22947
22948
22949/**
22950 * Set the rendering style. Note that since this is an immediate rendering API,
22951 * any `zIndex` on the provided style will be ignored.
22952 *
22953 * @param {ol.style.Style} style The rendering style.
22954 * @override
22955 * @api
22956 */
22957ol.render.canvas.Immediate.prototype.setStyle = function(style) {
22958 this.setFillStrokeStyle(style.getFill(), style.getStroke());
22959 this.setImageStyle(style.getImage());
22960 this.setTextStyle(style.getText());
22961};
22962
22963
22964/**
22965 * Render a geometry into the canvas. Call
22966 * {@link ol.render.canvas.Immediate#setStyle} first to set the rendering style.
22967 *
22968 * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.
22969 * @override
22970 * @api
22971 */
22972ol.render.canvas.Immediate.prototype.drawGeometry = function(geometry) {
22973 var type = geometry.getType();
22974 switch (type) {
22975 case ol.geom.GeometryType.POINT:
22976 this.drawPoint(/** @type {ol.geom.Point} */ (geometry));
22977 break;
22978 case ol.geom.GeometryType.LINE_STRING:
22979 this.drawLineString(/** @type {ol.geom.LineString} */ (geometry));
22980 break;
22981 case ol.geom.GeometryType.POLYGON:
22982 this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry));
22983 break;
22984 case ol.geom.GeometryType.MULTI_POINT:
22985 this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry));
22986 break;
22987 case ol.geom.GeometryType.MULTI_LINE_STRING:
22988 this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry));
22989 break;
22990 case ol.geom.GeometryType.MULTI_POLYGON:
22991 this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry));
22992 break;
22993 case ol.geom.GeometryType.GEOMETRY_COLLECTION:
22994 this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry));
22995 break;
22996 case ol.geom.GeometryType.CIRCLE:
22997 this.drawCircle(/** @type {ol.geom.Circle} */ (geometry));
22998 break;
22999 default:
23000 }
23001};
23002
23003
23004/**
23005 * Render a feature into the canvas. Note that any `zIndex` on the provided
23006 * style will be ignored - features are rendered immediately in the order that
23007 * this method is called. If you need `zIndex` support, you should be using an
23008 * {@link ol.layer.Vector} instead.
23009 *
23010 * @param {ol.Feature} feature Feature.
23011 * @param {ol.style.Style} style Style.
23012 * @override
23013 * @api
23014 */
23015ol.render.canvas.Immediate.prototype.drawFeature = function(feature, style) {
23016 var geometry = style.getGeometryFunction()(feature);
23017 if (!geometry ||
23018 !ol.extent.intersects(this.extent_, geometry.getExtent())) {
23019 return;
23020 }
23021 this.setStyle(style);
23022 this.drawGeometry(geometry);
23023};
23024
23025
23026/**
23027 * Render a GeometryCollection to the canvas. Rendering is immediate and
23028 * uses the current styles appropriate for each geometry in the collection.
23029 *
23030 * @param {ol.geom.GeometryCollection} geometry Geometry collection.
23031 * @override
23032 */
23033ol.render.canvas.Immediate.prototype.drawGeometryCollection = function(geometry) {
23034 var geometries = geometry.getGeometriesArray();
23035 var i, ii;
23036 for (i = 0, ii = geometries.length; i < ii; ++i) {
23037 this.drawGeometry(geometries[i]);
23038 }
23039};
23040
23041
23042/**
23043 * Render a Point geometry into the canvas. Rendering is immediate and uses
23044 * the current style.
23045 *
23046 * @param {ol.geom.Point|ol.render.Feature} geometry Point geometry.
23047 * @override
23048 */
23049ol.render.canvas.Immediate.prototype.drawPoint = function(geometry) {
23050 var flatCoordinates = geometry.getFlatCoordinates();
23051 var stride = geometry.getStride();
23052 if (this.image_) {
23053 this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
23054 }
23055 if (this.text_ !== '') {
23056 this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
23057 }
23058};
23059
23060
23061/**
23062 * Render a MultiPoint geometry into the canvas. Rendering is immediate and
23063 * uses the current style.
23064 *
23065 * @param {ol.geom.MultiPoint|ol.render.Feature} geometry MultiPoint geometry.
23066 * @override
23067 */
23068ol.render.canvas.Immediate.prototype.drawMultiPoint = function(geometry) {
23069 var flatCoordinates = geometry.getFlatCoordinates();
23070 var stride = geometry.getStride();
23071 if (this.image_) {
23072 this.drawImages_(flatCoordinates, 0, flatCoordinates.length, stride);
23073 }
23074 if (this.text_ !== '') {
23075 this.drawText_(flatCoordinates, 0, flatCoordinates.length, stride);
23076 }
23077};
23078
23079
23080/**
23081 * Render a LineString into the canvas. Rendering is immediate and uses
23082 * the current style.
23083 *
23084 * @param {ol.geom.LineString|ol.render.Feature} geometry LineString geometry.
23085 * @override
23086 */
23087ol.render.canvas.Immediate.prototype.drawLineString = function(geometry) {
23088 if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
23089 return;
23090 }
23091 if (this.strokeState_) {
23092 this.setContextStrokeState_(this.strokeState_);
23093 var context = this.context_;
23094 var flatCoordinates = geometry.getFlatCoordinates();
23095 context.beginPath();
23096 this.moveToLineTo_(flatCoordinates, 0, flatCoordinates.length,
23097 geometry.getStride(), false);
23098 context.stroke();
23099 }
23100 if (this.text_ !== '') {
23101 var flatMidpoint = geometry.getFlatMidpoint();
23102 this.drawText_(flatMidpoint, 0, 2, 2);
23103 }
23104};
23105
23106
23107/**
23108 * Render a MultiLineString geometry into the canvas. Rendering is immediate
23109 * and uses the current style.
23110 *
23111 * @param {ol.geom.MultiLineString|ol.render.Feature} geometry MultiLineString
23112 * geometry.
23113 * @override
23114 */
23115ol.render.canvas.Immediate.prototype.drawMultiLineString = function(geometry) {
23116 var geometryExtent = geometry.getExtent();
23117 if (!ol.extent.intersects(this.extent_, geometryExtent)) {
23118 return;
23119 }
23120 if (this.strokeState_) {
23121 this.setContextStrokeState_(this.strokeState_);
23122 var context = this.context_;
23123 var flatCoordinates = geometry.getFlatCoordinates();
23124 var offset = 0;
23125 var ends = geometry.getEnds();
23126 var stride = geometry.getStride();
23127 context.beginPath();
23128 var i, ii;
23129 for (i = 0, ii = ends.length; i < ii; ++i) {
23130 offset = this.moveToLineTo_(
23131 flatCoordinates, offset, ends[i], stride, false);
23132 }
23133 context.stroke();
23134 }
23135 if (this.text_ !== '') {
23136 var flatMidpoints = geometry.getFlatMidpoints();
23137 this.drawText_(flatMidpoints, 0, flatMidpoints.length, 2);
23138 }
23139};
23140
23141
23142/**
23143 * Render a Polygon geometry into the canvas. Rendering is immediate and uses
23144 * the current style.
23145 *
23146 * @param {ol.geom.Polygon|ol.render.Feature} geometry Polygon geometry.
23147 * @override
23148 */
23149ol.render.canvas.Immediate.prototype.drawPolygon = function(geometry) {
23150 if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
23151 return;
23152 }
23153 if (this.strokeState_ || this.fillState_) {
23154 if (this.fillState_) {
23155 this.setContextFillState_(this.fillState_);
23156 }
23157 if (this.strokeState_) {
23158 this.setContextStrokeState_(this.strokeState_);
23159 }
23160 var context = this.context_;
23161 context.beginPath();
23162 this.drawRings_(geometry.getOrientedFlatCoordinates(),
23163 0, geometry.getEnds(), geometry.getStride());
23164 if (this.fillState_) {
23165 context.fill();
23166 }
23167 if (this.strokeState_) {
23168 context.stroke();
23169 }
23170 }
23171 if (this.text_ !== '') {
23172 var flatInteriorPoint = geometry.getFlatInteriorPoint();
23173 this.drawText_(flatInteriorPoint, 0, 2, 2);
23174 }
23175};
23176
23177
23178/**
23179 * Render MultiPolygon geometry into the canvas. Rendering is immediate and
23180 * uses the current style.
23181 * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.
23182 * @override
23183 */
23184ol.render.canvas.Immediate.prototype.drawMultiPolygon = function(geometry) {
23185 if (!ol.extent.intersects(this.extent_, geometry.getExtent())) {
23186 return;
23187 }
23188 if (this.strokeState_ || this.fillState_) {
23189 if (this.fillState_) {
23190 this.setContextFillState_(this.fillState_);
23191 }
23192 if (this.strokeState_) {
23193 this.setContextStrokeState_(this.strokeState_);
23194 }
23195 var context = this.context_;
23196 var flatCoordinates = geometry.getOrientedFlatCoordinates();
23197 var offset = 0;
23198 var endss = geometry.getEndss();
23199 var stride = geometry.getStride();
23200 var i, ii;
23201 context.beginPath();
23202 for (i = 0, ii = endss.length; i < ii; ++i) {
23203 var ends = endss[i];
23204 offset = this.drawRings_(flatCoordinates, offset, ends, stride);
23205 }
23206 if (this.fillState_) {
23207 context.fill();
23208 }
23209 if (this.strokeState_) {
23210 context.stroke();
23211 }
23212 }
23213 if (this.text_ !== '') {
23214 var flatInteriorPoints = geometry.getFlatInteriorPoints();
23215 this.drawText_(flatInteriorPoints, 0, flatInteriorPoints.length, 2);
23216 }
23217};
23218
23219
23220/**
23221 * @param {ol.CanvasFillState} fillState Fill state.
23222 * @private
23223 */
23224ol.render.canvas.Immediate.prototype.setContextFillState_ = function(fillState) {
23225 var context = this.context_;
23226 var contextFillState = this.contextFillState_;
23227 if (!contextFillState) {
23228 context.fillStyle = fillState.fillStyle;
23229 this.contextFillState_ = {
23230 fillStyle: fillState.fillStyle
23231 };
23232 } else {
23233 if (contextFillState.fillStyle != fillState.fillStyle) {
23234 contextFillState.fillStyle = context.fillStyle = fillState.fillStyle;
23235 }
23236 }
23237};
23238
23239
23240/**
23241 * @param {ol.CanvasStrokeState} strokeState Stroke state.
23242 * @private
23243 */
23244ol.render.canvas.Immediate.prototype.setContextStrokeState_ = function(strokeState) {
23245 var context = this.context_;
23246 var contextStrokeState = this.contextStrokeState_;
23247 if (!contextStrokeState) {
23248 context.lineCap = strokeState.lineCap;
23249 if (ol.has.CANVAS_LINE_DASH) {
23250 context.setLineDash(strokeState.lineDash);
23251 context.lineDashOffset = strokeState.lineDashOffset;
23252 }
23253 context.lineJoin = strokeState.lineJoin;
23254 context.lineWidth = strokeState.lineWidth;
23255 context.miterLimit = strokeState.miterLimit;
23256 context.strokeStyle = strokeState.strokeStyle;
23257 this.contextStrokeState_ = {
23258 lineCap: strokeState.lineCap,
23259 lineDash: strokeState.lineDash,
23260 lineDashOffset: strokeState.lineDashOffset,
23261 lineJoin: strokeState.lineJoin,
23262 lineWidth: strokeState.lineWidth,
23263 miterLimit: strokeState.miterLimit,
23264 strokeStyle: strokeState.strokeStyle
23265 };
23266 } else {
23267 if (contextStrokeState.lineCap != strokeState.lineCap) {
23268 contextStrokeState.lineCap = context.lineCap = strokeState.lineCap;
23269 }
23270 if (ol.has.CANVAS_LINE_DASH) {
23271 if (!ol.array.equals(
23272 contextStrokeState.lineDash, strokeState.lineDash)) {
23273 context.setLineDash(contextStrokeState.lineDash = strokeState.lineDash);
23274 }
23275 if (contextStrokeState.lineDashOffset != strokeState.lineDashOffset) {
23276 contextStrokeState.lineDashOffset = context.lineDashOffset =
23277 strokeState.lineDashOffset;
23278 }
23279 }
23280 if (contextStrokeState.lineJoin != strokeState.lineJoin) {
23281 contextStrokeState.lineJoin = context.lineJoin = strokeState.lineJoin;
23282 }
23283 if (contextStrokeState.lineWidth != strokeState.lineWidth) {
23284 contextStrokeState.lineWidth = context.lineWidth = strokeState.lineWidth;
23285 }
23286 if (contextStrokeState.miterLimit != strokeState.miterLimit) {
23287 contextStrokeState.miterLimit = context.miterLimit =
23288 strokeState.miterLimit;
23289 }
23290 if (contextStrokeState.strokeStyle != strokeState.strokeStyle) {
23291 contextStrokeState.strokeStyle = context.strokeStyle =
23292 strokeState.strokeStyle;
23293 }
23294 }
23295};
23296
23297
23298/**
23299 * @param {ol.CanvasTextState} textState Text state.
23300 * @private
23301 */
23302ol.render.canvas.Immediate.prototype.setContextTextState_ = function(textState) {
23303 var context = this.context_;
23304 var contextTextState = this.contextTextState_;
23305 if (!contextTextState) {
23306 context.font = textState.font;
23307 context.textAlign = textState.textAlign;
23308 context.textBaseline = textState.textBaseline;
23309 this.contextTextState_ = {
23310 font: textState.font,
23311 textAlign: textState.textAlign,
23312 textBaseline: textState.textBaseline
23313 };
23314 } else {
23315 if (contextTextState.font != textState.font) {
23316 contextTextState.font = context.font = textState.font;
23317 }
23318 if (contextTextState.textAlign != textState.textAlign) {
23319 contextTextState.textAlign = context.textAlign = textState.textAlign;
23320 }
23321 if (contextTextState.textBaseline != textState.textBaseline) {
23322 contextTextState.textBaseline = context.textBaseline =
23323 textState.textBaseline;
23324 }
23325 }
23326};
23327
23328
23329/**
23330 * Set the fill and stroke style for subsequent draw operations. To clear
23331 * either fill or stroke styles, pass null for the appropriate parameter.
23332 *
23333 * @param {ol.style.Fill} fillStyle Fill style.
23334 * @param {ol.style.Stroke} strokeStyle Stroke style.
23335 * @override
23336 */
23337ol.render.canvas.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
23338 if (!fillStyle) {
23339 this.fillState_ = null;
23340 } else {
23341 var fillStyleColor = fillStyle.getColor();
23342 this.fillState_ = {
23343 fillStyle: ol.colorlike.asColorLike(fillStyleColor ?
23344 fillStyleColor : ol.render.canvas.defaultFillStyle)
23345 };
23346 }
23347 if (!strokeStyle) {
23348 this.strokeState_ = null;
23349 } else {
23350 var strokeStyleColor = strokeStyle.getColor();
23351 var strokeStyleLineCap = strokeStyle.getLineCap();
23352 var strokeStyleLineDash = strokeStyle.getLineDash();
23353 var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
23354 var strokeStyleLineJoin = strokeStyle.getLineJoin();
23355 var strokeStyleWidth = strokeStyle.getWidth();
23356 var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
23357 this.strokeState_ = {
23358 lineCap: strokeStyleLineCap !== undefined ?
23359 strokeStyleLineCap : ol.render.canvas.defaultLineCap,
23360 lineDash: strokeStyleLineDash ?
23361 strokeStyleLineDash : ol.render.canvas.defaultLineDash,
23362 lineDashOffset: strokeStyleLineDashOffset ?
23363 strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset,
23364 lineJoin: strokeStyleLineJoin !== undefined ?
23365 strokeStyleLineJoin : ol.render.canvas.defaultLineJoin,
23366 lineWidth: this.pixelRatio_ * (strokeStyleWidth !== undefined ?
23367 strokeStyleWidth : ol.render.canvas.defaultLineWidth),
23368 miterLimit: strokeStyleMiterLimit !== undefined ?
23369 strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,
23370 strokeStyle: ol.colorlike.asColorLike(strokeStyleColor ?
23371 strokeStyleColor : ol.render.canvas.defaultStrokeStyle)
23372 };
23373 }
23374};
23375
23376
23377/**
23378 * Set the image style for subsequent draw operations. Pass null to remove
23379 * the image style.
23380 *
23381 * @param {ol.style.Image} imageStyle Image style.
23382 * @override
23383 */
23384ol.render.canvas.Immediate.prototype.setImageStyle = function(imageStyle) {
23385 if (!imageStyle) {
23386 this.image_ = null;
23387 } else {
23388 var imageAnchor = imageStyle.getAnchor();
23389 // FIXME pixel ratio
23390 var imageImage = imageStyle.getImage(1);
23391 var imageOrigin = imageStyle.getOrigin();
23392 var imageSize = imageStyle.getSize();
23393 this.imageAnchorX_ = imageAnchor[0];
23394 this.imageAnchorY_ = imageAnchor[1];
23395 this.imageHeight_ = imageSize[1];
23396 this.image_ = imageImage;
23397 this.imageOpacity_ = imageStyle.getOpacity();
23398 this.imageOriginX_ = imageOrigin[0];
23399 this.imageOriginY_ = imageOrigin[1];
23400 this.imageRotateWithView_ = imageStyle.getRotateWithView();
23401 this.imageRotation_ = imageStyle.getRotation();
23402 this.imageScale_ = imageStyle.getScale() * this.pixelRatio_;
23403 this.imageSnapToPixel_ = imageStyle.getSnapToPixel();
23404 this.imageWidth_ = imageSize[0];
23405 }
23406};
23407
23408
23409/**
23410 * Set the text style for subsequent draw operations. Pass null to
23411 * remove the text style.
23412 *
23413 * @param {ol.style.Text} textStyle Text style.
23414 * @override
23415 */
23416ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) {
23417 if (!textStyle) {
23418 this.text_ = '';
23419 } else {
23420 var textFillStyle = textStyle.getFill();
23421 if (!textFillStyle) {
23422 this.textFillState_ = null;
23423 } else {
23424 var textFillStyleColor = textFillStyle.getColor();
23425 this.textFillState_ = {
23426 fillStyle: ol.colorlike.asColorLike(textFillStyleColor ?
23427 textFillStyleColor : ol.render.canvas.defaultFillStyle)
23428 };
23429 }
23430 var textStrokeStyle = textStyle.getStroke();
23431 if (!textStrokeStyle) {
23432 this.textStrokeState_ = null;
23433 } else {
23434 var textStrokeStyleColor = textStrokeStyle.getColor();
23435 var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
23436 var textStrokeStyleLineDash = textStrokeStyle.getLineDash();
23437 var textStrokeStyleLineDashOffset = textStrokeStyle.getLineDashOffset();
23438 var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
23439 var textStrokeStyleWidth = textStrokeStyle.getWidth();
23440 var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
23441 this.textStrokeState_ = {
23442 lineCap: textStrokeStyleLineCap !== undefined ?
23443 textStrokeStyleLineCap : ol.render.canvas.defaultLineCap,
23444 lineDash: textStrokeStyleLineDash ?
23445 textStrokeStyleLineDash : ol.render.canvas.defaultLineDash,
23446 lineDashOffset: textStrokeStyleLineDashOffset ?
23447 textStrokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset,
23448 lineJoin: textStrokeStyleLineJoin !== undefined ?
23449 textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin,
23450 lineWidth: textStrokeStyleWidth !== undefined ?
23451 textStrokeStyleWidth : ol.render.canvas.defaultLineWidth,
23452 miterLimit: textStrokeStyleMiterLimit !== undefined ?
23453 textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit,
23454 strokeStyle: ol.colorlike.asColorLike(textStrokeStyleColor ?
23455 textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle)
23456 };
23457 }
23458 var textFont = textStyle.getFont();
23459 var textOffsetX = textStyle.getOffsetX();
23460 var textOffsetY = textStyle.getOffsetY();
23461 var textRotateWithView = textStyle.getRotateWithView();
23462 var textRotation = textStyle.getRotation();
23463 var textScale = textStyle.getScale();
23464 var textText = textStyle.getText();
23465 var textTextAlign = textStyle.getTextAlign();
23466 var textTextBaseline = textStyle.getTextBaseline();
23467 this.textState_ = {
23468 font: textFont !== undefined ?
23469 textFont : ol.render.canvas.defaultFont,
23470 textAlign: textTextAlign !== undefined ?
23471 textTextAlign : ol.render.canvas.defaultTextAlign,
23472 textBaseline: textTextBaseline !== undefined ?
23473 textTextBaseline : ol.render.canvas.defaultTextBaseline
23474 };
23475 this.text_ = textText !== undefined ? textText : '';
23476 this.textOffsetX_ =
23477 textOffsetX !== undefined ? (this.pixelRatio_ * textOffsetX) : 0;
23478 this.textOffsetY_ =
23479 textOffsetY !== undefined ? (this.pixelRatio_ * textOffsetY) : 0;
23480 this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
23481 this.textRotation_ = textRotation !== undefined ? textRotation : 0;
23482 this.textScale_ = this.pixelRatio_ * (textScale !== undefined ?
23483 textScale : 1);
23484 }
23485};
23486
23487// FIXME offset panning
23488
23489goog.provide('ol.renderer.canvas.Map');
23490
23491goog.require('ol.transform');
23492goog.require('ol');
23493goog.require('ol.array');
23494goog.require('ol.css');
23495goog.require('ol.dom');
23496goog.require('ol.layer.Layer');
23497goog.require('ol.render.Event');
23498goog.require('ol.render.EventType');
23499goog.require('ol.render.canvas');
23500goog.require('ol.render.canvas.Immediate');
23501goog.require('ol.renderer.Map');
23502goog.require('ol.renderer.Type');
23503goog.require('ol.source.State');
23504
23505
23506/**
23507 * @constructor
23508 * @extends {ol.renderer.Map}
23509 * @param {Element} container Container.
23510 * @param {ol.Map} map Map.
23511 */
23512ol.renderer.canvas.Map = function(container, map) {
23513
23514 ol.renderer.Map.call(this, container, map);
23515
23516 /**
23517 * @private
23518 * @type {CanvasRenderingContext2D}
23519 */
23520 this.context_ = ol.dom.createCanvasContext2D();
23521
23522 /**
23523 * @private
23524 * @type {HTMLCanvasElement}
23525 */
23526 this.canvas_ = this.context_.canvas;
23527
23528 this.canvas_.style.width = '100%';
23529 this.canvas_.style.height = '100%';
23530 this.canvas_.style.display = 'block';
23531 this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
23532 container.insertBefore(this.canvas_, container.childNodes[0] || null);
23533
23534 /**
23535 * @private
23536 * @type {boolean}
23537 */
23538 this.renderedVisible_ = true;
23539
23540 /**
23541 * @private
23542 * @type {ol.Transform}
23543 */
23544 this.transform_ = ol.transform.create();
23545
23546};
23547ol.inherits(ol.renderer.canvas.Map, ol.renderer.Map);
23548
23549
23550/**
23551 * @param {ol.render.EventType} type Event type.
23552 * @param {olx.FrameState} frameState Frame state.
23553 * @private
23554 */
23555ol.renderer.canvas.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {
23556 var map = this.getMap();
23557 var context = this.context_;
23558 if (map.hasListener(type)) {
23559 var extent = frameState.extent;
23560 var pixelRatio = frameState.pixelRatio;
23561 var viewState = frameState.viewState;
23562 var rotation = viewState.rotation;
23563
23564 var transform = this.getTransform(frameState);
23565
23566 var vectorContext = new ol.render.canvas.Immediate(context, pixelRatio,
23567 extent, transform, rotation);
23568 var composeEvent = new ol.render.Event(type, vectorContext,
23569 frameState, context, null);
23570 map.dispatchEvent(composeEvent);
23571 }
23572};
23573
23574
23575/**
23576 * @param {olx.FrameState} frameState Frame state.
23577 * @protected
23578 * @return {!ol.Transform} Transform.
23579 */
23580ol.renderer.canvas.Map.prototype.getTransform = function(frameState) {
23581 var viewState = frameState.viewState;
23582 var dx1 = this.canvas_.width / 2;
23583 var dy1 = this.canvas_.height / 2;
23584 var sx = frameState.pixelRatio / viewState.resolution;
23585 var sy = -sx;
23586 var angle = -viewState.rotation;
23587 var dx2 = -viewState.center[0];
23588 var dy2 = -viewState.center[1];
23589 return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);
23590};
23591
23592
23593/**
23594 * @inheritDoc
23595 */
23596ol.renderer.canvas.Map.prototype.getType = function() {
23597 return ol.renderer.Type.CANVAS;
23598};
23599
23600
23601/**
23602 * @inheritDoc
23603 */
23604ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {
23605
23606 if (!frameState) {
23607 if (this.renderedVisible_) {
23608 this.canvas_.style.display = 'none';
23609 this.renderedVisible_ = false;
23610 }
23611 return;
23612 }
23613
23614 var context = this.context_;
23615 var pixelRatio = frameState.pixelRatio;
23616 var width = Math.round(frameState.size[0] * pixelRatio);
23617 var height = Math.round(frameState.size[1] * pixelRatio);
23618 if (this.canvas_.width != width || this.canvas_.height != height) {
23619 this.canvas_.width = width;
23620 this.canvas_.height = height;
23621 } else {
23622 context.clearRect(0, 0, width, height);
23623 }
23624
23625 var rotation = frameState.viewState.rotation;
23626
23627 this.calculateMatrices2D(frameState);
23628
23629 this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
23630
23631 var layerStatesArray = frameState.layerStatesArray;
23632 ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
23633
23634 if (rotation) {
23635 context.save();
23636 ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
23637 }
23638
23639 var viewResolution = frameState.viewState.resolution;
23640 var i, ii, layer, layerRenderer, layerState;
23641 for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
23642 layerState = layerStatesArray[i];
23643 layer = layerState.layer;
23644 layerRenderer = /** @type {ol.renderer.canvas.Layer} */ (this.getLayerRenderer(layer));
23645 if (!ol.layer.Layer.visibleAtResolution(layerState, viewResolution) ||
23646 layerState.sourceState != ol.source.State.READY) {
23647 continue;
23648 }
23649 if (layerRenderer.prepareFrame(frameState, layerState)) {
23650 layerRenderer.composeFrame(frameState, layerState, context);
23651 }
23652 }
23653
23654 if (rotation) {
23655 context.restore();
23656 }
23657
23658 this.dispatchComposeEvent_(
23659 ol.render.EventType.POSTCOMPOSE, frameState);
23660
23661 if (!this.renderedVisible_) {
23662 this.canvas_.style.display = '';
23663 this.renderedVisible_ = true;
23664 }
23665
23666 this.scheduleRemoveUnusedLayerRenderers(frameState);
23667 this.scheduleExpireIconCache(frameState);
23668};
23669
23670
23671/**
23672 * @inheritDoc
23673 */
23674ol.renderer.canvas.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
23675 layerFilter, thisArg2) {
23676 var result;
23677 var viewState = frameState.viewState;
23678 var viewResolution = viewState.resolution;
23679
23680 var layerStates = frameState.layerStatesArray;
23681 var numLayers = layerStates.length;
23682
23683 var coordinate = ol.transform.apply(
23684 frameState.pixelToCoordinateTransform, pixel.slice());
23685
23686 var i;
23687 for (i = numLayers - 1; i >= 0; --i) {
23688 var layerState = layerStates[i];
23689 var layer = layerState.layer;
23690 if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
23691 layerFilter.call(thisArg2, layer)) {
23692 var layerRenderer = /** @type {ol.renderer.canvas.Layer} */ (this.getLayerRenderer(layer));
23693 result = layerRenderer.forEachLayerAtCoordinate(
23694 coordinate, frameState, callback, thisArg);
23695 if (result) {
23696 return result;
23697 }
23698 }
23699 }
23700 return undefined;
23701};
23702
23703goog.provide('ol.render.ReplayType');
23704
23705
23706/**
23707 * @enum {string}
23708 */
23709ol.render.ReplayType = {
23710 CIRCLE: 'Circle',
23711 DEFAULT: 'Default',
23712 IMAGE: 'Image',
23713 LINE_STRING: 'LineString',
23714 POLYGON: 'Polygon',
23715 TEXT: 'Text'
23716};
23717
23718goog.provide('ol.render.replay');
23719
23720goog.require('ol.render.ReplayType');
23721
23722
23723/**
23724 * @const
23725 * @type {Array.<ol.render.ReplayType>}
23726 */
23727ol.render.replay.ORDER = [
23728 ol.render.ReplayType.POLYGON,
23729 ol.render.ReplayType.CIRCLE,
23730 ol.render.ReplayType.LINE_STRING,
23731 ol.render.ReplayType.IMAGE,
23732 ol.render.ReplayType.TEXT,
23733 ol.render.ReplayType.DEFAULT
23734];
23735
23736goog.provide('ol.render.ReplayGroup');
23737
23738
23739/**
23740 * Base class for replay groups.
23741 * @constructor
23742 * @abstract
23743 */
23744ol.render.ReplayGroup = function() {};
23745
23746
23747/**
23748 * @abstract
23749 * @param {number|undefined} zIndex Z index.
23750 * @param {ol.render.ReplayType} replayType Replay type.
23751 * @return {ol.render.VectorContext} Replay.
23752 */
23753ol.render.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {};
23754
23755
23756/**
23757 * @abstract
23758 * @return {boolean} Is empty.
23759 */
23760ol.render.ReplayGroup.prototype.isEmpty = function() {};
23761
23762goog.provide('ol.webgl.Shader');
23763
23764goog.require('ol');
23765goog.require('ol.functions');
23766
23767
23768if (ol.ENABLE_WEBGL) {
23769
23770 /**
23771 * @constructor
23772 * @abstract
23773 * @param {string} source Source.
23774 * @struct
23775 */
23776 ol.webgl.Shader = function(source) {
23777
23778 /**
23779 * @private
23780 * @type {string}
23781 */
23782 this.source_ = source;
23783
23784 };
23785
23786
23787 /**
23788 * @abstract
23789 * @return {number} Type.
23790 */
23791 ol.webgl.Shader.prototype.getType = function() {};
23792
23793
23794 /**
23795 * @return {string} Source.
23796 */
23797 ol.webgl.Shader.prototype.getSource = function() {
23798 return this.source_;
23799 };
23800
23801
23802 /**
23803 * @return {boolean} Is animated?
23804 */
23805 ol.webgl.Shader.prototype.isAnimated = ol.functions.FALSE;
23806
23807}
23808
23809goog.provide('ol.webgl.Fragment');
23810
23811goog.require('ol');
23812goog.require('ol.webgl');
23813goog.require('ol.webgl.Shader');
23814
23815
23816if (ol.ENABLE_WEBGL) {
23817
23818 /**
23819 * @constructor
23820 * @extends {ol.webgl.Shader}
23821 * @param {string} source Source.
23822 * @struct
23823 */
23824 ol.webgl.Fragment = function(source) {
23825 ol.webgl.Shader.call(this, source);
23826 };
23827 ol.inherits(ol.webgl.Fragment, ol.webgl.Shader);
23828
23829
23830 /**
23831 * @inheritDoc
23832 */
23833 ol.webgl.Fragment.prototype.getType = function() {
23834 return ol.webgl.FRAGMENT_SHADER;
23835 };
23836
23837}
23838
23839goog.provide('ol.webgl.Vertex');
23840
23841goog.require('ol');
23842goog.require('ol.webgl');
23843goog.require('ol.webgl.Shader');
23844
23845
23846if (ol.ENABLE_WEBGL) {
23847
23848 /**
23849 * @constructor
23850 * @extends {ol.webgl.Shader}
23851 * @param {string} source Source.
23852 * @struct
23853 */
23854 ol.webgl.Vertex = function(source) {
23855 ol.webgl.Shader.call(this, source);
23856 };
23857 ol.inherits(ol.webgl.Vertex, ol.webgl.Shader);
23858
23859
23860 /**
23861 * @inheritDoc
23862 */
23863 ol.webgl.Vertex.prototype.getType = function() {
23864 return ol.webgl.VERTEX_SHADER;
23865 };
23866
23867}
23868
23869// This file is automatically generated, do not edit
23870/* eslint openlayers-internal/no-missing-requires: 0 */
23871goog.provide('ol.render.webgl.circlereplay.defaultshader');
23872
23873goog.require('ol');
23874goog.require('ol.webgl.Fragment');
23875goog.require('ol.webgl.Vertex');
23876
23877if (ol.ENABLE_WEBGL) {
23878
23879 /**
23880 * @constructor
23881 * @extends {ol.webgl.Fragment}
23882 * @struct
23883 */
23884 ol.render.webgl.circlereplay.defaultshader.Fragment = function() {
23885 ol.webgl.Fragment.call(this, ol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE);
23886 };
23887 ol.inherits(ol.render.webgl.circlereplay.defaultshader.Fragment, ol.webgl.Fragment);
23888
23889
23890 /**
23891 * @const
23892 * @type {string}
23893 */
23894 ol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_center;\nvarying vec2 v_offset;\nvarying float v_halfWidth;\nvarying float v_pixelRatio;\n\n\n\nuniform float u_opacity;\nuniform vec4 u_fillColor;\nuniform vec4 u_strokeColor;\nuniform vec2 u_size;\n\nvoid main(void) {\n vec2 windowCenter = vec2((v_center.x + 1.0) / 2.0 * u_size.x * v_pixelRatio,\n (v_center.y + 1.0) / 2.0 * u_size.y * v_pixelRatio);\n vec2 windowOffset = vec2((v_offset.x + 1.0) / 2.0 * u_size.x * v_pixelRatio,\n (v_offset.y + 1.0) / 2.0 * u_size.y * v_pixelRatio);\n float radius = length(windowCenter - windowOffset);\n float dist = length(windowCenter - gl_FragCoord.xy);\n if (dist > radius + v_halfWidth) {\n if (u_strokeColor.a == 0.0) {\n gl_FragColor = u_fillColor;\n } else {\n gl_FragColor = u_strokeColor;\n }\n gl_FragColor.a = gl_FragColor.a - (dist - (radius + v_halfWidth));\n } else if (u_fillColor.a == 0.0) {\n // Hooray, no fill, just stroke. We can use real antialiasing.\n gl_FragColor = u_strokeColor;\n if (dist < radius - v_halfWidth) {\n gl_FragColor.a = gl_FragColor.a - (radius - v_halfWidth - dist);\n }\n } else {\n gl_FragColor = u_fillColor;\n float strokeDist = radius - v_halfWidth;\n float antialias = 2.0 * v_pixelRatio;\n if (dist > strokeDist) {\n gl_FragColor = u_strokeColor;\n } else if (dist >= strokeDist - antialias) {\n float step = smoothstep(strokeDist - antialias, strokeDist, dist);\n gl_FragColor = mix(u_fillColor, u_strokeColor, step);\n }\n }\n gl_FragColor.a = gl_FragColor.a * u_opacity;\n if (gl_FragColor.a <= 0.0) {\n discard;\n }\n}\n';
23895
23896
23897 /**
23898 * @const
23899 * @type {string}
23900 */
23901 ol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;varying vec2 b;varying float c;varying float d;uniform float m;uniform vec4 n;uniform vec4 o;uniform vec2 p;void main(void){vec2 windowCenter=vec2((a.x+1.0)/2.0*p.x*d,(a.y+1.0)/2.0*p.y*d);vec2 windowOffset=vec2((b.x+1.0)/2.0*p.x*d,(b.y+1.0)/2.0*p.y*d);float radius=length(windowCenter-windowOffset);float dist=length(windowCenter-gl_FragCoord.xy);if(dist>radius+c){if(o.a==0.0){gl_FragColor=n;}else{gl_FragColor=o;}gl_FragColor.a=gl_FragColor.a-(dist-(radius+c));}else if(n.a==0.0){gl_FragColor=o;if(dist<radius-c){gl_FragColor.a=gl_FragColor.a-(radius-c-dist);}} else{gl_FragColor=n;float strokeDist=radius-c;float antialias=2.0*d;if(dist>strokeDist){gl_FragColor=o;}else if(dist>=strokeDist-antialias){float step=smoothstep(strokeDist-antialias,strokeDist,dist);gl_FragColor=mix(n,o,step);}} gl_FragColor.a=gl_FragColor.a*m;if(gl_FragColor.a<=0.0){discard;}}';
23902
23903
23904 /**
23905 * @const
23906 * @type {string}
23907 */
23908 ol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
23909 ol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE :
23910 ol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE;
23911
23912
23913 ol.render.webgl.circlereplay.defaultshader.fragment = new ol.render.webgl.circlereplay.defaultshader.Fragment();
23914
23915
23916 /**
23917 * @constructor
23918 * @extends {ol.webgl.Vertex}
23919 * @struct
23920 */
23921 ol.render.webgl.circlereplay.defaultshader.Vertex = function() {
23922 ol.webgl.Vertex.call(this, ol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE);
23923 };
23924 ol.inherits(ol.render.webgl.circlereplay.defaultshader.Vertex, ol.webgl.Vertex);
23925
23926
23927 /**
23928 * @const
23929 * @type {string}
23930 */
23931 ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_center;\nvarying vec2 v_offset;\nvarying float v_halfWidth;\nvarying float v_pixelRatio;\n\n\nattribute vec2 a_position;\nattribute float a_instruction;\nattribute float a_radius;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_lineWidth;\nuniform float u_pixelRatio;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n v_center = vec4(u_projectionMatrix * vec4(a_position, 0.0, 1.0)).xy;\n v_pixelRatio = u_pixelRatio;\n float lineWidth = u_lineWidth * u_pixelRatio;\n v_halfWidth = lineWidth / 2.0;\n if (lineWidth == 0.0) {\n lineWidth = 2.0 * u_pixelRatio;\n }\n vec2 offset;\n // Radius with anitaliasing (roughly).\n float radius = a_radius + 3.0 * u_pixelRatio;\n // Until we get gl_VertexID in WebGL, we store an instruction.\n if (a_instruction == 0.0) {\n // Offsetting the edges of the triangle by lineWidth / 2 is necessary, however\n // we should also leave some space for the antialiasing, thus we offset by lineWidth.\n offset = vec2(-1.0, 1.0);\n } else if (a_instruction == 1.0) {\n offset = vec2(-1.0, -1.0);\n } else if (a_instruction == 2.0) {\n offset = vec2(1.0, -1.0);\n } else {\n offset = vec2(1.0, 1.0);\n }\n\n gl_Position = u_projectionMatrix * vec4(a_position + offset * radius, 0.0, 1.0) +\n offsetMatrix * vec4(offset * lineWidth, 0.0, 0.0);\n v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y,\n 0.0, 1.0)).xy;\n\n if (distance(v_center, v_offset) > 20000.0) {\n gl_Position = vec4(v_center, 0.0, 1.0);\n }\n}\n\n\n';
23932
23933
23934 /**
23935 * @const
23936 * @type {string}
23937 */
23938 ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying vec2 b;varying float c;varying float d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;void main(void){mat4 offsetMatrix=i*j;a=vec4(h*vec4(e,0.0,1.0)).xy;d=l;float lineWidth=k*l;c=lineWidth/2.0;if(lineWidth==0.0){lineWidth=2.0*l;}vec2 offset;float radius=g+3.0*l;if(f==0.0){offset=vec2(-1.0,1.0);}else if(f==1.0){offset=vec2(-1.0,-1.0);}else if(f==2.0){offset=vec2(1.0,-1.0);}else{offset=vec2(1.0,1.0);}gl_Position=h*vec4(e+offset*radius,0.0,1.0)+offsetMatrix*vec4(offset*lineWidth,0.0,0.0);b=vec4(h*vec4(e.x+g,e.y,0.0,1.0)).xy;if(distance(a,b)>20000.0){gl_Position=vec4(a,0.0,1.0);}}';
23939
23940
23941 /**
23942 * @const
23943 * @type {string}
23944 */
23945 ol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
23946 ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE :
23947 ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE;
23948
23949
23950 ol.render.webgl.circlereplay.defaultshader.vertex = new ol.render.webgl.circlereplay.defaultshader.Vertex();
23951
23952
23953 /**
23954 * @constructor
23955 * @param {WebGLRenderingContext} gl GL.
23956 * @param {WebGLProgram} program Program.
23957 * @struct
23958 */
23959 ol.render.webgl.circlereplay.defaultshader.Locations = function(gl, program) {
23960
23961 /**
23962 * @type {WebGLUniformLocation}
23963 */
23964 this.u_fillColor = gl.getUniformLocation(
23965 program, ol.DEBUG_WEBGL ? 'u_fillColor' : 'n');
23966
23967 /**
23968 * @type {WebGLUniformLocation}
23969 */
23970 this.u_lineWidth = gl.getUniformLocation(
23971 program, ol.DEBUG_WEBGL ? 'u_lineWidth' : 'k');
23972
23973 /**
23974 * @type {WebGLUniformLocation}
23975 */
23976 this.u_offsetRotateMatrix = gl.getUniformLocation(
23977 program, ol.DEBUG_WEBGL ? 'u_offsetRotateMatrix' : 'j');
23978
23979 /**
23980 * @type {WebGLUniformLocation}
23981 */
23982 this.u_offsetScaleMatrix = gl.getUniformLocation(
23983 program, ol.DEBUG_WEBGL ? 'u_offsetScaleMatrix' : 'i');
23984
23985 /**
23986 * @type {WebGLUniformLocation}
23987 */
23988 this.u_opacity = gl.getUniformLocation(
23989 program, ol.DEBUG_WEBGL ? 'u_opacity' : 'm');
23990
23991 /**
23992 * @type {WebGLUniformLocation}
23993 */
23994 this.u_pixelRatio = gl.getUniformLocation(
23995 program, ol.DEBUG_WEBGL ? 'u_pixelRatio' : 'l');
23996
23997 /**
23998 * @type {WebGLUniformLocation}
23999 */
24000 this.u_projectionMatrix = gl.getUniformLocation(
24001 program, ol.DEBUG_WEBGL ? 'u_projectionMatrix' : 'h');
24002
24003 /**
24004 * @type {WebGLUniformLocation}
24005 */
24006 this.u_size = gl.getUniformLocation(
24007 program, ol.DEBUG_WEBGL ? 'u_size' : 'p');
24008
24009 /**
24010 * @type {WebGLUniformLocation}
24011 */
24012 this.u_strokeColor = gl.getUniformLocation(
24013 program, ol.DEBUG_WEBGL ? 'u_strokeColor' : 'o');
24014
24015 /**
24016 * @type {number}
24017 */
24018 this.a_instruction = gl.getAttribLocation(
24019 program, ol.DEBUG_WEBGL ? 'a_instruction' : 'f');
24020
24021 /**
24022 * @type {number}
24023 */
24024 this.a_position = gl.getAttribLocation(
24025 program, ol.DEBUG_WEBGL ? 'a_position' : 'e');
24026
24027 /**
24028 * @type {number}
24029 */
24030 this.a_radius = gl.getAttribLocation(
24031 program, ol.DEBUG_WEBGL ? 'a_radius' : 'g');
24032 };
24033
24034}
24035
24036goog.provide('ol.vec.Mat4');
24037
24038
24039/**
24040 * @return {Array.<number>} 4x4 matrix representing a 3D identity transform.
24041 */
24042ol.vec.Mat4.create = function() {
24043 return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
24044};
24045
24046
24047/**
24048 * @param {Array.<number>} mat4 Flattened 4x4 matrix receiving the result.
24049 * @param {ol.Transform} transform Transformation matrix.
24050 * @return {Array.<number>} 2D transformation matrix as flattened 4x4 matrix.
24051 */
24052ol.vec.Mat4.fromTransform = function(mat4, transform) {
24053 mat4[0] = transform[0];
24054 mat4[1] = transform[1];
24055 mat4[4] = transform[2];
24056 mat4[5] = transform[3];
24057 mat4[12] = transform[4];
24058 mat4[13] = transform[5];
24059 return mat4;
24060};
24061
24062goog.provide('ol.render.webgl.Replay');
24063
24064goog.require('ol');
24065goog.require('ol.extent');
24066goog.require('ol.render.VectorContext');
24067goog.require('ol.transform');
24068goog.require('ol.vec.Mat4');
24069goog.require('ol.webgl');
24070
24071
24072if (ol.ENABLE_WEBGL) {
24073
24074 /**
24075 * @constructor
24076 * @abstract
24077 * @extends {ol.render.VectorContext}
24078 * @param {number} tolerance Tolerance.
24079 * @param {ol.Extent} maxExtent Max extent.
24080 * @struct
24081 */
24082 ol.render.webgl.Replay = function(tolerance, maxExtent) {
24083 ol.render.VectorContext.call(this);
24084
24085 /**
24086 * @protected
24087 * @type {number}
24088 */
24089 this.tolerance = tolerance;
24090
24091 /**
24092 * @protected
24093 * @const
24094 * @type {ol.Extent}
24095 */
24096 this.maxExtent = maxExtent;
24097
24098 /**
24099 * The origin of the coordinate system for the point coordinates sent to
24100 * the GPU. To eliminate jitter caused by precision problems in the GPU
24101 * we use the "Rendering Relative to Eye" technique described in the "3D
24102 * Engine Design for Virtual Globes" book.
24103 * @protected
24104 * @type {ol.Coordinate}
24105 */
24106 this.origin = ol.extent.getCenter(maxExtent);
24107
24108 /**
24109 * @private
24110 * @type {ol.Transform}
24111 */
24112 this.projectionMatrix_ = ol.transform.create();
24113
24114 /**
24115 * @private
24116 * @type {ol.Transform}
24117 */
24118 this.offsetRotateMatrix_ = ol.transform.create();
24119
24120 /**
24121 * @private
24122 * @type {ol.Transform}
24123 */
24124 this.offsetScaleMatrix_ = ol.transform.create();
24125
24126 /**
24127 * @private
24128 * @type {Array.<number>}
24129 */
24130 this.tmpMat4_ = ol.vec.Mat4.create();
24131
24132 /**
24133 * @protected
24134 * @type {Array.<number>}
24135 */
24136 this.indices = [];
24137
24138 /**
24139 * @protected
24140 * @type {?ol.webgl.Buffer}
24141 */
24142 this.indicesBuffer = null;
24143
24144 /**
24145 * Start index per feature (the index).
24146 * @protected
24147 * @type {Array.<number>}
24148 */
24149 this.startIndices = [];
24150
24151 /**
24152 * Start index per feature (the feature).
24153 * @protected
24154 * @type {Array.<ol.Feature|ol.render.Feature>}
24155 */
24156 this.startIndicesFeature = [];
24157
24158 /**
24159 * @protected
24160 * @type {Array.<number>}
24161 */
24162 this.vertices = [];
24163
24164 /**
24165 * @protected
24166 * @type {?ol.webgl.Buffer}
24167 */
24168 this.verticesBuffer = null;
24169
24170 /**
24171 * Optional parameter for PolygonReplay instances.
24172 * @protected
24173 * @type {ol.render.webgl.LineStringReplay|undefined}
24174 */
24175 this.lineStringReplay = undefined;
24176
24177 };
24178 ol.inherits(ol.render.webgl.Replay, ol.render.VectorContext);
24179
24180
24181 /**
24182 * @abstract
24183 * @param {ol.webgl.Context} context WebGL context.
24184 * @return {function()} Delete resources function.
24185 */
24186 ol.render.webgl.Replay.prototype.getDeleteResourcesFunction = function(context) {};
24187
24188
24189 /**
24190 * @abstract
24191 * @param {ol.webgl.Context} context Context.
24192 */
24193 ol.render.webgl.Replay.prototype.finish = function(context) {};
24194
24195
24196 /**
24197 * @abstract
24198 * @protected
24199 * @param {WebGLRenderingContext} gl gl.
24200 * @param {ol.webgl.Context} context Context.
24201 * @param {ol.Size} size Size.
24202 * @param {number} pixelRatio Pixel ratio.
24203 * @return {ol.render.webgl.circlereplay.defaultshader.Locations|
24204 ol.render.webgl.linestringreplay.defaultshader.Locations|
24205 ol.render.webgl.polygonreplay.defaultshader.Locations|
24206 ol.render.webgl.texturereplay.defaultshader.Locations} Locations.
24207 */
24208 ol.render.webgl.Replay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {};
24209
24210
24211 /**
24212 * @abstract
24213 * @protected
24214 * @param {WebGLRenderingContext} gl gl.
24215 * @param {ol.render.webgl.circlereplay.defaultshader.Locations|
24216 ol.render.webgl.linestringreplay.defaultshader.Locations|
24217 ol.render.webgl.polygonreplay.defaultshader.Locations|
24218 ol.render.webgl.texturereplay.defaultshader.Locations} locations Locations.
24219 */
24220 ol.render.webgl.Replay.prototype.shutDownProgram = function(gl, locations) {};
24221
24222
24223 /**
24224 * @abstract
24225 * @protected
24226 * @param {WebGLRenderingContext} gl gl.
24227 * @param {ol.webgl.Context} context Context.
24228 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
24229 * to skip.
24230 * @param {boolean} hitDetection Hit detection mode.
24231 */
24232 ol.render.webgl.Replay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {};
24233
24234
24235 /**
24236 * @abstract
24237 * @protected
24238 * @param {WebGLRenderingContext} gl gl.
24239 * @param {ol.webgl.Context} context Context.
24240 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
24241 * to skip.
24242 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
24243 * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
24244 * this extent are checked.
24245 * @return {T|undefined} Callback result.
24246 * @template T
24247 */
24248 ol.render.webgl.Replay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) {};
24249
24250
24251 /**
24252 * @protected
24253 * @param {WebGLRenderingContext} gl gl.
24254 * @param {ol.webgl.Context} context Context.
24255 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
24256 * to skip.
24257 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
24258 * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
24259 * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
24260 * this extent are checked.
24261 * @return {T|undefined} Callback result.
24262 * @template T
24263 */
24264 ol.render.webgl.Replay.prototype.drawHitDetectionReplay = function(gl, context, skippedFeaturesHash,
24265 featureCallback, oneByOne, opt_hitExtent) {
24266 if (!oneByOne) {
24267 // draw all hit-detection features in "once" (by texture group)
24268 return this.drawHitDetectionReplayAll(gl, context,
24269 skippedFeaturesHash, featureCallback);
24270 } else {
24271 // draw hit-detection features one by one
24272 return this.drawHitDetectionReplayOneByOne(gl, context,
24273 skippedFeaturesHash, featureCallback, opt_hitExtent);
24274 }
24275 };
24276
24277
24278 /**
24279 * @protected
24280 * @param {WebGLRenderingContext} gl gl.
24281 * @param {ol.webgl.Context} context Context.
24282 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
24283 * to skip.
24284 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
24285 * @return {T|undefined} Callback result.
24286 * @template T
24287 */
24288 ol.render.webgl.Replay.prototype.drawHitDetectionReplayAll = function(gl, context, skippedFeaturesHash,
24289 featureCallback) {
24290 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
24291 this.drawReplay(gl, context, skippedFeaturesHash, true);
24292
24293 var result = featureCallback(null);
24294 if (result) {
24295 return result;
24296 } else {
24297 return undefined;
24298 }
24299 };
24300
24301
24302 /**
24303 * @param {ol.webgl.Context} context Context.
24304 * @param {ol.Coordinate} center Center.
24305 * @param {number} resolution Resolution.
24306 * @param {number} rotation Rotation.
24307 * @param {ol.Size} size Size.
24308 * @param {number} pixelRatio Pixel ratio.
24309 * @param {number} opacity Global opacity.
24310 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
24311 * to skip.
24312 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
24313 * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
24314 * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
24315 * this extent are checked.
24316 * @return {T|undefined} Callback result.
24317 * @template T
24318 */
24319 ol.render.webgl.Replay.prototype.replay = function(context,
24320 center, resolution, rotation, size, pixelRatio,
24321 opacity, skippedFeaturesHash,
24322 featureCallback, oneByOne, opt_hitExtent) {
24323 var gl = context.getGL();
24324 var tmpStencil, tmpStencilFunc, tmpStencilMaskVal, tmpStencilRef, tmpStencilMask,
24325 tmpStencilOpFail, tmpStencilOpPass, tmpStencilOpZFail;
24326
24327 if (this.lineStringReplay) {
24328 tmpStencil = gl.isEnabled(gl.STENCIL_TEST);
24329 tmpStencilFunc = gl.getParameter(gl.STENCIL_FUNC);
24330 tmpStencilMaskVal = gl.getParameter(gl.STENCIL_VALUE_MASK);
24331 tmpStencilRef = gl.getParameter(gl.STENCIL_REF);
24332 tmpStencilMask = gl.getParameter(gl.STENCIL_WRITEMASK);
24333 tmpStencilOpFail = gl.getParameter(gl.STENCIL_FAIL);
24334 tmpStencilOpPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS);
24335 tmpStencilOpZFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL);
24336
24337 gl.enable(gl.STENCIL_TEST);
24338 gl.clear(gl.STENCIL_BUFFER_BIT);
24339 gl.stencilMask(255);
24340 gl.stencilFunc(gl.ALWAYS, 1, 255);
24341 gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
24342
24343 this.lineStringReplay.replay(context,
24344 center, resolution, rotation, size, pixelRatio,
24345 opacity, skippedFeaturesHash,
24346 featureCallback, oneByOne, opt_hitExtent);
24347
24348 gl.stencilMask(0);
24349 gl.stencilFunc(gl.NOTEQUAL, 1, 255);
24350 }
24351
24352 context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.verticesBuffer);
24353
24354 context.bindBuffer(ol.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
24355
24356 var locations = this.setUpProgram(gl, context, size, pixelRatio);
24357
24358 // set the "uniform" values
24359 var projectionMatrix = ol.transform.reset(this.projectionMatrix_);
24360 ol.transform.scale(projectionMatrix, 2 / (resolution * size[0]), 2 / (resolution * size[1]));
24361 ol.transform.rotate(projectionMatrix, -rotation);
24362 ol.transform.translate(projectionMatrix, -(center[0] - this.origin[0]), -(center[1] - this.origin[1]));
24363
24364 var offsetScaleMatrix = ol.transform.reset(this.offsetScaleMatrix_);
24365 ol.transform.scale(offsetScaleMatrix, 2 / size[0], 2 / size[1]);
24366
24367 var offsetRotateMatrix = ol.transform.reset(this.offsetRotateMatrix_);
24368 if (rotation !== 0) {
24369 ol.transform.rotate(offsetRotateMatrix, -rotation);
24370 }
24371
24372 gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
24373 ol.vec.Mat4.fromTransform(this.tmpMat4_, projectionMatrix));
24374 gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false,
24375 ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetScaleMatrix));
24376 gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false,
24377 ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetRotateMatrix));
24378 gl.uniform1f(locations.u_opacity, opacity);
24379
24380 // draw!
24381 var result;
24382 if (featureCallback === undefined) {
24383 this.drawReplay(gl, context, skippedFeaturesHash, false);
24384 } else {
24385 // draw feature by feature for the hit-detection
24386 result = this.drawHitDetectionReplay(gl, context, skippedFeaturesHash,
24387 featureCallback, oneByOne, opt_hitExtent);
24388 }
24389
24390 // disable the vertex attrib arrays
24391 this.shutDownProgram(gl, locations);
24392
24393 if (this.lineStringReplay) {
24394 if (!tmpStencil) {
24395 gl.disable(gl.STENCIL_TEST);
24396 }
24397 gl.clear(gl.STENCIL_BUFFER_BIT);
24398 gl.stencilFunc(/** @type {number} */ (tmpStencilFunc),
24399 /** @type {number} */ (tmpStencilRef), /** @type {number} */ (tmpStencilMaskVal));
24400 gl.stencilMask(/** @type {number} */ (tmpStencilMask));
24401 gl.stencilOp(/** @type {number} */ (tmpStencilOpFail),
24402 /** @type {number} */ (tmpStencilOpZFail), /** @type {number} */ (tmpStencilOpPass));
24403 }
24404
24405 return result;
24406 };
24407
24408 /**
24409 * @protected
24410 * @param {WebGLRenderingContext} gl gl.
24411 * @param {ol.webgl.Context} context Context.
24412 * @param {number} start Start index.
24413 * @param {number} end End index.
24414 */
24415 ol.render.webgl.Replay.prototype.drawElements = function(
24416 gl, context, start, end) {
24417 var elementType = context.hasOESElementIndexUint ?
24418 ol.webgl.UNSIGNED_INT : ol.webgl.UNSIGNED_SHORT;
24419 var elementSize = context.hasOESElementIndexUint ? 4 : 2;
24420
24421 var numItems = end - start;
24422 var offsetInBytes = start * elementSize;
24423 gl.drawElements(ol.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
24424 };
24425
24426}
24427
24428goog.provide('ol.render.webgl');
24429
24430goog.require('ol');
24431
24432
24433if (ol.ENABLE_WEBGL) {
24434
24435 /**
24436 * @const
24437 * @type {string}
24438 */
24439 ol.render.webgl.defaultFont = '10px sans-serif';
24440
24441
24442 /**
24443 * @const
24444 * @type {ol.Color}
24445 */
24446 ol.render.webgl.defaultFillStyle = [0.0, 0.0, 0.0, 1.0];
24447
24448
24449 /**
24450 * @const
24451 * @type {string}
24452 */
24453 ol.render.webgl.defaultLineCap = 'round';
24454
24455
24456 /**
24457 * @const
24458 * @type {Array.<number>}
24459 */
24460 ol.render.webgl.defaultLineDash = [];
24461
24462
24463 /**
24464 * @const
24465 * @type {number}
24466 */
24467 ol.render.webgl.defaultLineDashOffset = 0;
24468
24469
24470 /**
24471 * @const
24472 * @type {string}
24473 */
24474 ol.render.webgl.defaultLineJoin = 'round';
24475
24476
24477 /**
24478 * @const
24479 * @type {number}
24480 */
24481 ol.render.webgl.defaultMiterLimit = 10;
24482
24483 /**
24484 * @const
24485 * @type {ol.Color}
24486 */
24487 ol.render.webgl.defaultStrokeStyle = [0.0, 0.0, 0.0, 1.0];
24488
24489
24490 /**
24491 * @const
24492 * @type {number}
24493 */
24494 ol.render.webgl.defaultTextAlign = 0.5;
24495
24496
24497 /**
24498 * @const
24499 * @type {number}
24500 */
24501 ol.render.webgl.defaultTextBaseline = 0.5;
24502
24503
24504 /**
24505 * @const
24506 * @type {number}
24507 */
24508 ol.render.webgl.defaultLineWidth = 1;
24509
24510 /**
24511 * Calculates the orientation of a triangle based on the determinant method.
24512 * @param {number} x1 First X coordinate.
24513 * @param {number} y1 First Y coordinate.
24514 * @param {number} x2 Second X coordinate.
24515 * @param {number} y2 Second Y coordinate.
24516 * @param {number} x3 Third X coordinate.
24517 * @param {number} y3 Third Y coordinate.
24518 * @return {boolean|undefined} Triangle is clockwise.
24519 */
24520 ol.render.webgl.triangleIsCounterClockwise = function(x1, y1, x2, y2, x3, y3) {
24521 var area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
24522 return (area <= ol.render.webgl.EPSILON && area >= -ol.render.webgl.EPSILON) ?
24523 undefined : area > 0;
24524 };
24525
24526 /**
24527 * @const
24528 * @type {number}
24529 */
24530 ol.render.webgl.EPSILON = Number.EPSILON || 2.220446049250313e-16;
24531
24532}
24533
24534goog.provide('ol.webgl.Buffer');
24535
24536goog.require('ol');
24537goog.require('ol.webgl');
24538
24539
24540if (ol.ENABLE_WEBGL) {
24541
24542 /**
24543 * @constructor
24544 * @param {Array.<number>=} opt_arr Array.
24545 * @param {number=} opt_usage Usage.
24546 * @struct
24547 */
24548 ol.webgl.Buffer = function(opt_arr, opt_usage) {
24549
24550 /**
24551 * @private
24552 * @type {Array.<number>}
24553 */
24554 this.arr_ = opt_arr !== undefined ? opt_arr : [];
24555
24556 /**
24557 * @private
24558 * @type {number}
24559 */
24560 this.usage_ = opt_usage !== undefined ?
24561 opt_usage : ol.webgl.Buffer.Usage_.STATIC_DRAW;
24562
24563 };
24564
24565
24566 /**
24567 * @return {Array.<number>} Array.
24568 */
24569 ol.webgl.Buffer.prototype.getArray = function() {
24570 return this.arr_;
24571 };
24572
24573
24574 /**
24575 * @return {number} Usage.
24576 */
24577 ol.webgl.Buffer.prototype.getUsage = function() {
24578 return this.usage_;
24579 };
24580
24581
24582 /**
24583 * @enum {number}
24584 * @private
24585 */
24586 ol.webgl.Buffer.Usage_ = {
24587 STATIC_DRAW: ol.webgl.STATIC_DRAW,
24588 STREAM_DRAW: ol.webgl.STREAM_DRAW,
24589 DYNAMIC_DRAW: ol.webgl.DYNAMIC_DRAW
24590 };
24591
24592}
24593
24594goog.provide('ol.render.webgl.CircleReplay');
24595
24596goog.require('ol');
24597goog.require('ol.array');
24598goog.require('ol.color');
24599goog.require('ol.extent');
24600goog.require('ol.obj');
24601goog.require('ol.geom.flat.transform');
24602goog.require('ol.render.webgl.circlereplay.defaultshader');
24603goog.require('ol.render.webgl.Replay');
24604goog.require('ol.render.webgl');
24605goog.require('ol.webgl');
24606goog.require('ol.webgl.Buffer');
24607
24608
24609if (ol.ENABLE_WEBGL) {
24610
24611 /**
24612 * @constructor
24613 * @extends {ol.render.webgl.Replay}
24614 * @param {number} tolerance Tolerance.
24615 * @param {ol.Extent} maxExtent Max extent.
24616 * @struct
24617 */
24618 ol.render.webgl.CircleReplay = function(tolerance, maxExtent) {
24619 ol.render.webgl.Replay.call(this, tolerance, maxExtent);
24620
24621 /**
24622 * @private
24623 * @type {ol.render.webgl.circlereplay.defaultshader.Locations}
24624 */
24625 this.defaultLocations_ = null;
24626
24627 /**
24628 * @private
24629 * @type {Array.<Array.<Array.<number>|number>>}
24630 */
24631 this.styles_ = [];
24632
24633 /**
24634 * @private
24635 * @type {Array.<number>}
24636 */
24637 this.styleIndices_ = [];
24638
24639 /**
24640 * @private
24641 * @type {number}
24642 */
24643 this.radius_ = 0;
24644
24645 /**
24646 * @private
24647 * @type {{fillColor: (Array.<number>|null),
24648 * strokeColor: (Array.<number>|null),
24649 * lineDash: Array.<number>,
24650 * lineDashOffset: (number|undefined),
24651 * lineWidth: (number|undefined),
24652 * changed: boolean}|null}
24653 */
24654 this.state_ = {
24655 fillColor: null,
24656 strokeColor: null,
24657 lineDash: null,
24658 lineDashOffset: undefined,
24659 lineWidth: undefined,
24660 changed: false
24661 };
24662
24663 };
24664 ol.inherits(ol.render.webgl.CircleReplay, ol.render.webgl.Replay);
24665
24666
24667 /**
24668 * @private
24669 * @param {Array.<number>} flatCoordinates Flat coordinates.
24670 * @param {number} offset Offset.
24671 * @param {number} end End.
24672 * @param {number} stride Stride.
24673 */
24674 ol.render.webgl.CircleReplay.prototype.drawCoordinates_ = function(
24675 flatCoordinates, offset, end, stride) {
24676 var numVertices = this.vertices.length;
24677 var numIndices = this.indices.length;
24678 var n = numVertices / 4;
24679 var i, ii;
24680 for (i = offset, ii = end; i < ii; i += stride) {
24681 this.vertices[numVertices++] = flatCoordinates[i];
24682 this.vertices[numVertices++] = flatCoordinates[i + 1];
24683 this.vertices[numVertices++] = 0;
24684 this.vertices[numVertices++] = this.radius_;
24685
24686 this.vertices[numVertices++] = flatCoordinates[i];
24687 this.vertices[numVertices++] = flatCoordinates[i + 1];
24688 this.vertices[numVertices++] = 1;
24689 this.vertices[numVertices++] = this.radius_;
24690
24691 this.vertices[numVertices++] = flatCoordinates[i];
24692 this.vertices[numVertices++] = flatCoordinates[i + 1];
24693 this.vertices[numVertices++] = 2;
24694 this.vertices[numVertices++] = this.radius_;
24695
24696 this.vertices[numVertices++] = flatCoordinates[i];
24697 this.vertices[numVertices++] = flatCoordinates[i + 1];
24698 this.vertices[numVertices++] = 3;
24699 this.vertices[numVertices++] = this.radius_;
24700
24701 this.indices[numIndices++] = n;
24702 this.indices[numIndices++] = n + 1;
24703 this.indices[numIndices++] = n + 2;
24704
24705 this.indices[numIndices++] = n + 2;
24706 this.indices[numIndices++] = n + 3;
24707 this.indices[numIndices++] = n;
24708
24709 n += 4;
24710 }
24711 };
24712
24713
24714 /**
24715 * @inheritDoc
24716 */
24717 ol.render.webgl.CircleReplay.prototype.drawCircle = function(circleGeometry, feature) {
24718 var radius = circleGeometry.getRadius();
24719 var stride = circleGeometry.getStride();
24720 if (radius) {
24721 this.startIndices.push(this.indices.length);
24722 this.startIndicesFeature.push(feature);
24723 if (this.state_.changed) {
24724 this.styleIndices_.push(this.indices.length);
24725 this.state_.changed = false;
24726 }
24727
24728 this.radius_ = radius;
24729 var flatCoordinates = circleGeometry.getFlatCoordinates();
24730 flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, 2,
24731 stride, -this.origin[0], -this.origin[1]);
24732 this.drawCoordinates_(flatCoordinates, 0, 2, stride);
24733 } else {
24734 if (this.state_.changed) {
24735 this.styles_.pop();
24736 if (this.styles_.length) {
24737 var lastState = this.styles_[this.styles_.length - 1];
24738 this.state_.fillColor = /** @type {Array.<number>} */ (lastState[0]);
24739 this.state_.strokeColor = /** @type {Array.<number>} */ (lastState[1]);
24740 this.state_.lineWidth = /** @type {number} */ (lastState[2]);
24741 this.state_.changed = false;
24742 }
24743 }
24744 }
24745 };
24746
24747
24748 /**
24749 * @inheritDoc
24750 **/
24751 ol.render.webgl.CircleReplay.prototype.finish = function(context) {
24752 // create, bind, and populate the vertices buffer
24753 this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
24754
24755 // create, bind, and populate the indices buffer
24756 this.indicesBuffer = new ol.webgl.Buffer(this.indices);
24757
24758 this.startIndices.push(this.indices.length);
24759
24760 //Clean up, if there is nothing to draw
24761 if (this.styleIndices_.length === 0 && this.styles_.length > 0) {
24762 this.styles_ = [];
24763 }
24764
24765 this.vertices = null;
24766 this.indices = null;
24767 };
24768
24769
24770 /**
24771 * @inheritDoc
24772 */
24773 ol.render.webgl.CircleReplay.prototype.getDeleteResourcesFunction = function(context) {
24774 // We only delete our stuff here. The shaders and the program may
24775 // be used by other CircleReplay instances (for other layers). And
24776 // they will be deleted when disposing of the ol.webgl.Context
24777 // object.
24778 var verticesBuffer = this.verticesBuffer;
24779 var indicesBuffer = this.indicesBuffer;
24780 return function() {
24781 context.deleteBuffer(verticesBuffer);
24782 context.deleteBuffer(indicesBuffer);
24783 };
24784 };
24785
24786
24787 /**
24788 * @inheritDoc
24789 */
24790 ol.render.webgl.CircleReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {
24791 // get the program
24792 var fragmentShader, vertexShader;
24793 fragmentShader = ol.render.webgl.circlereplay.defaultshader.fragment;
24794 vertexShader = ol.render.webgl.circlereplay.defaultshader.vertex;
24795 var program = context.getProgram(fragmentShader, vertexShader);
24796
24797 // get the locations
24798 var locations;
24799 if (!this.defaultLocations_) {
24800 // eslint-disable-next-line openlayers-internal/no-missing-requires
24801 locations = new ol.render.webgl.circlereplay.defaultshader.Locations(gl, program);
24802 this.defaultLocations_ = locations;
24803 } else {
24804 locations = this.defaultLocations_;
24805 }
24806
24807 context.useProgram(program);
24808
24809 // enable the vertex attrib arrays
24810 gl.enableVertexAttribArray(locations.a_position);
24811 gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,
24812 false, 16, 0);
24813
24814 gl.enableVertexAttribArray(locations.a_instruction);
24815 gl.vertexAttribPointer(locations.a_instruction, 1, ol.webgl.FLOAT,
24816 false, 16, 8);
24817
24818 gl.enableVertexAttribArray(locations.a_radius);
24819 gl.vertexAttribPointer(locations.a_radius, 1, ol.webgl.FLOAT,
24820 false, 16, 12);
24821
24822 // Enable renderer specific uniforms.
24823 gl.uniform2fv(locations.u_size, size);
24824 gl.uniform1f(locations.u_pixelRatio, pixelRatio);
24825
24826 return locations;
24827 };
24828
24829
24830 /**
24831 * @inheritDoc
24832 */
24833 ol.render.webgl.CircleReplay.prototype.shutDownProgram = function(gl, locations) {
24834 gl.disableVertexAttribArray(locations.a_position);
24835 gl.disableVertexAttribArray(locations.a_instruction);
24836 gl.disableVertexAttribArray(locations.a_radius);
24837 };
24838
24839
24840 /**
24841 * @inheritDoc
24842 */
24843 ol.render.webgl.CircleReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {
24844 if (!ol.obj.isEmpty(skippedFeaturesHash)) {
24845 this.drawReplaySkipping_(gl, context, skippedFeaturesHash);
24846 } else {
24847 //Draw by style groups to minimize drawElements() calls.
24848 var i, start, end, nextStyle;
24849 end = this.startIndices[this.startIndices.length - 1];
24850 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
24851 start = this.styleIndices_[i];
24852 nextStyle = this.styles_[i];
24853 this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
24854 this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
24855 /** @type {number} */ (nextStyle[2]));
24856 this.drawElements(gl, context, start, end);
24857 end = start;
24858 }
24859 }
24860 };
24861
24862
24863 /**
24864 * @inheritDoc
24865 */
24866 ol.render.webgl.CircleReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,
24867 featureCallback, opt_hitExtent) {
24868 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;
24869 featureIndex = this.startIndices.length - 2;
24870 end = this.startIndices[featureIndex + 1];
24871 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
24872 nextStyle = this.styles_[i];
24873 this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
24874 this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
24875 /** @type {number} */ (nextStyle[2]));
24876 groupStart = this.styleIndices_[i];
24877
24878 while (featureIndex >= 0 &&
24879 this.startIndices[featureIndex] >= groupStart) {
24880 start = this.startIndices[featureIndex];
24881 feature = this.startIndicesFeature[featureIndex];
24882 featureUid = ol.getUid(feature).toString();
24883
24884 if (skippedFeaturesHash[featureUid] === undefined &&
24885 feature.getGeometry() &&
24886 (opt_hitExtent === undefined || ol.extent.intersects(
24887 /** @type {Array<number>} */ (opt_hitExtent),
24888 feature.getGeometry().getExtent()))) {
24889 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
24890 this.drawElements(gl, context, start, end);
24891
24892 var result = featureCallback(feature);
24893
24894 if (result) {
24895 return result;
24896 }
24897
24898 }
24899 featureIndex--;
24900 end = start;
24901 }
24902 }
24903 return undefined;
24904 };
24905
24906
24907 /**
24908 * @private
24909 * @param {WebGLRenderingContext} gl gl.
24910 * @param {ol.webgl.Context} context Context.
24911 * @param {Object} skippedFeaturesHash Ids of features to skip.
24912 */
24913 ol.render.webgl.CircleReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {
24914 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;
24915 featureIndex = this.startIndices.length - 2;
24916 end = start = this.startIndices[featureIndex + 1];
24917 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
24918 nextStyle = this.styles_[i];
24919 this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
24920 this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
24921 /** @type {number} */ (nextStyle[2]));
24922 groupStart = this.styleIndices_[i];
24923
24924 while (featureIndex >= 0 &&
24925 this.startIndices[featureIndex] >= groupStart) {
24926 featureStart = this.startIndices[featureIndex];
24927 feature = this.startIndicesFeature[featureIndex];
24928 featureUid = ol.getUid(feature).toString();
24929
24930 if (skippedFeaturesHash[featureUid]) {
24931 if (start !== end) {
24932 this.drawElements(gl, context, start, end);
24933 }
24934 end = featureStart;
24935 }
24936 featureIndex--;
24937 start = featureStart;
24938 }
24939 if (start !== end) {
24940 this.drawElements(gl, context, start, end);
24941 }
24942 start = end = groupStart;
24943 }
24944 };
24945
24946
24947 /**
24948 * @private
24949 * @param {WebGLRenderingContext} gl gl.
24950 * @param {Array.<number>} color Color.
24951 */
24952 ol.render.webgl.CircleReplay.prototype.setFillStyle_ = function(gl, color) {
24953 gl.uniform4fv(this.defaultLocations_.u_fillColor, color);
24954 };
24955
24956
24957 /**
24958 * @private
24959 * @param {WebGLRenderingContext} gl gl.
24960 * @param {Array.<number>} color Color.
24961 * @param {number} lineWidth Line width.
24962 */
24963 ol.render.webgl.CircleReplay.prototype.setStrokeStyle_ = function(gl, color, lineWidth) {
24964 gl.uniform4fv(this.defaultLocations_.u_strokeColor, color);
24965 gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth);
24966 };
24967
24968
24969 /**
24970 * @inheritDoc
24971 */
24972 ol.render.webgl.CircleReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
24973 var strokeStyleColor, strokeStyleWidth;
24974 if (strokeStyle) {
24975 var strokeStyleLineDash = strokeStyle.getLineDash();
24976 this.state_.lineDash = strokeStyleLineDash ?
24977 strokeStyleLineDash : ol.render.webgl.defaultLineDash;
24978 var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
24979 this.state_.lineDashOffset = strokeStyleLineDashOffset ?
24980 strokeStyleLineDashOffset : ol.render.webgl.defaultLineDashOffset;
24981 strokeStyleColor = strokeStyle.getColor();
24982 if (!(strokeStyleColor instanceof CanvasGradient) &&
24983 !(strokeStyleColor instanceof CanvasPattern)) {
24984 strokeStyleColor = ol.color.asArray(strokeStyleColor).map(function(c, i) {
24985 return i != 3 ? c / 255 : c;
24986 }) || ol.render.webgl.defaultStrokeStyle;
24987 } else {
24988 strokeStyleColor = ol.render.webgl.defaultStrokeStyle;
24989 }
24990 strokeStyleWidth = strokeStyle.getWidth();
24991 strokeStyleWidth = strokeStyleWidth !== undefined ?
24992 strokeStyleWidth : ol.render.webgl.defaultLineWidth;
24993 } else {
24994 strokeStyleColor = [0, 0, 0, 0];
24995 strokeStyleWidth = 0;
24996 }
24997 var fillStyleColor = fillStyle ? fillStyle.getColor() : [0, 0, 0, 0];
24998 if (!(fillStyleColor instanceof CanvasGradient) &&
24999 !(fillStyleColor instanceof CanvasPattern)) {
25000 fillStyleColor = ol.color.asArray(fillStyleColor).map(function(c, i) {
25001 return i != 3 ? c / 255 : c;
25002 }) || ol.render.webgl.defaultFillStyle;
25003 } else {
25004 fillStyleColor = ol.render.webgl.defaultFillStyle;
25005 }
25006 if (!this.state_.strokeColor || !ol.array.equals(this.state_.strokeColor, strokeStyleColor) ||
25007 !this.state_.fillColor || !ol.array.equals(this.state_.fillColor, fillStyleColor) ||
25008 this.state_.lineWidth !== strokeStyleWidth) {
25009 this.state_.changed = true;
25010 this.state_.fillColor = fillStyleColor;
25011 this.state_.strokeColor = strokeStyleColor;
25012 this.state_.lineWidth = strokeStyleWidth;
25013 this.styles_.push([fillStyleColor, strokeStyleColor, strokeStyleWidth]);
25014 }
25015 };
25016
25017}
25018
25019// This file is automatically generated, do not edit
25020/* eslint openlayers-internal/no-missing-requires: 0 */
25021goog.provide('ol.render.webgl.texturereplay.defaultshader');
25022
25023goog.require('ol');
25024goog.require('ol.webgl.Fragment');
25025goog.require('ol.webgl.Vertex');
25026
25027if (ol.ENABLE_WEBGL) {
25028
25029 /**
25030 * @constructor
25031 * @extends {ol.webgl.Fragment}
25032 * @struct
25033 */
25034 ol.render.webgl.texturereplay.defaultshader.Fragment = function() {
25035 ol.webgl.Fragment.call(this, ol.render.webgl.texturereplay.defaultshader.Fragment.SOURCE);
25036 };
25037 ol.inherits(ol.render.webgl.texturereplay.defaultshader.Fragment, ol.webgl.Fragment);
25038
25039
25040 /**
25041 * @const
25042 * @type {string}
25043 */
25044 ol.render.webgl.texturereplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\nvarying float v_opacity;\n\nuniform float u_opacity;\nuniform sampler2D u_image;\n\nvoid main(void) {\n vec4 texColor = texture2D(u_image, v_texCoord);\n gl_FragColor.rgb = texColor.rgb;\n float alpha = texColor.a * v_opacity * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n';
25045
25046
25047 /**
25048 * @const
25049 * @type {string}
25050 */
25051 ol.render.webgl.texturereplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;varying float b;uniform float k;uniform sampler2D l;void main(void){vec4 texColor=texture2D(l,a);gl_FragColor.rgb=texColor.rgb;float alpha=texColor.a*b*k;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';
25052
25053
25054 /**
25055 * @const
25056 * @type {string}
25057 */
25058 ol.render.webgl.texturereplay.defaultshader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
25059 ol.render.webgl.texturereplay.defaultshader.Fragment.DEBUG_SOURCE :
25060 ol.render.webgl.texturereplay.defaultshader.Fragment.OPTIMIZED_SOURCE;
25061
25062
25063 ol.render.webgl.texturereplay.defaultshader.fragment = new ol.render.webgl.texturereplay.defaultshader.Fragment();
25064
25065
25066 /**
25067 * @constructor
25068 * @extends {ol.webgl.Vertex}
25069 * @struct
25070 */
25071 ol.render.webgl.texturereplay.defaultshader.Vertex = function() {
25072 ol.webgl.Vertex.call(this, ol.render.webgl.texturereplay.defaultshader.Vertex.SOURCE);
25073 };
25074 ol.inherits(ol.render.webgl.texturereplay.defaultshader.Vertex, ol.webgl.Vertex);
25075
25076
25077 /**
25078 * @const
25079 * @type {string}
25080 */
25081 ol.render.webgl.texturereplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\nvarying float v_opacity;\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\nattribute vec2 a_offsets;\nattribute float a_opacity;\nattribute float a_rotateWithView;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix;\n if (a_rotateWithView == 1.0) {\n offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n }\n vec4 offsets = offsetMatrix * vec4(a_offsets, 0.0, 0.0);\n gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\n v_texCoord = a_texCoord;\n v_opacity = a_opacity;\n}\n\n\n';
25082
25083
25084 /**
25085 * @const
25086 * @type {string}
25087 */
25088 ol.render.webgl.texturereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying float b;attribute vec2 c;attribute vec2 d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;void main(void){mat4 offsetMatrix=i;if(g==1.0){offsetMatrix=i*j;}vec4 offsets=offsetMatrix*vec4(e,0.0,0.0);gl_Position=h*vec4(c,0.0,1.0)+offsets;a=d;b=f;}';
25089
25090
25091 /**
25092 * @const
25093 * @type {string}
25094 */
25095 ol.render.webgl.texturereplay.defaultshader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
25096 ol.render.webgl.texturereplay.defaultshader.Vertex.DEBUG_SOURCE :
25097 ol.render.webgl.texturereplay.defaultshader.Vertex.OPTIMIZED_SOURCE;
25098
25099
25100 ol.render.webgl.texturereplay.defaultshader.vertex = new ol.render.webgl.texturereplay.defaultshader.Vertex();
25101
25102
25103 /**
25104 * @constructor
25105 * @param {WebGLRenderingContext} gl GL.
25106 * @param {WebGLProgram} program Program.
25107 * @struct
25108 */
25109 ol.render.webgl.texturereplay.defaultshader.Locations = function(gl, program) {
25110
25111 /**
25112 * @type {WebGLUniformLocation}
25113 */
25114 this.u_image = gl.getUniformLocation(
25115 program, ol.DEBUG_WEBGL ? 'u_image' : 'l');
25116
25117 /**
25118 * @type {WebGLUniformLocation}
25119 */
25120 this.u_offsetRotateMatrix = gl.getUniformLocation(
25121 program, ol.DEBUG_WEBGL ? 'u_offsetRotateMatrix' : 'j');
25122
25123 /**
25124 * @type {WebGLUniformLocation}
25125 */
25126 this.u_offsetScaleMatrix = gl.getUniformLocation(
25127 program, ol.DEBUG_WEBGL ? 'u_offsetScaleMatrix' : 'i');
25128
25129 /**
25130 * @type {WebGLUniformLocation}
25131 */
25132 this.u_opacity = gl.getUniformLocation(
25133 program, ol.DEBUG_WEBGL ? 'u_opacity' : 'k');
25134
25135 /**
25136 * @type {WebGLUniformLocation}
25137 */
25138 this.u_projectionMatrix = gl.getUniformLocation(
25139 program, ol.DEBUG_WEBGL ? 'u_projectionMatrix' : 'h');
25140
25141 /**
25142 * @type {number}
25143 */
25144 this.a_offsets = gl.getAttribLocation(
25145 program, ol.DEBUG_WEBGL ? 'a_offsets' : 'e');
25146
25147 /**
25148 * @type {number}
25149 */
25150 this.a_opacity = gl.getAttribLocation(
25151 program, ol.DEBUG_WEBGL ? 'a_opacity' : 'f');
25152
25153 /**
25154 * @type {number}
25155 */
25156 this.a_position = gl.getAttribLocation(
25157 program, ol.DEBUG_WEBGL ? 'a_position' : 'c');
25158
25159 /**
25160 * @type {number}
25161 */
25162 this.a_rotateWithView = gl.getAttribLocation(
25163 program, ol.DEBUG_WEBGL ? 'a_rotateWithView' : 'g');
25164
25165 /**
25166 * @type {number}
25167 */
25168 this.a_texCoord = gl.getAttribLocation(
25169 program, ol.DEBUG_WEBGL ? 'a_texCoord' : 'd');
25170 };
25171
25172}
25173
25174goog.provide('ol.webgl.ContextEventType');
25175
25176
25177/**
25178 * @enum {string}
25179 */
25180ol.webgl.ContextEventType = {
25181 LOST: 'webglcontextlost',
25182 RESTORED: 'webglcontextrestored'
25183};
25184
25185goog.provide('ol.webgl.Context');
25186
25187goog.require('ol');
25188goog.require('ol.Disposable');
25189goog.require('ol.array');
25190goog.require('ol.events');
25191goog.require('ol.obj');
25192goog.require('ol.webgl');
25193goog.require('ol.webgl.ContextEventType');
25194
25195
25196if (ol.ENABLE_WEBGL) {
25197
25198 /**
25199 * @classdesc
25200 * A WebGL context for accessing low-level WebGL capabilities.
25201 *
25202 * @constructor
25203 * @extends {ol.Disposable}
25204 * @param {HTMLCanvasElement} canvas Canvas.
25205 * @param {WebGLRenderingContext} gl GL.
25206 */
25207 ol.webgl.Context = function(canvas, gl) {
25208
25209 /**
25210 * @private
25211 * @type {HTMLCanvasElement}
25212 */
25213 this.canvas_ = canvas;
25214
25215 /**
25216 * @private
25217 * @type {WebGLRenderingContext}
25218 */
25219 this.gl_ = gl;
25220
25221 /**
25222 * @private
25223 * @type {Object.<string, ol.WebglBufferCacheEntry>}
25224 */
25225 this.bufferCache_ = {};
25226
25227 /**
25228 * @private
25229 * @type {Object.<string, WebGLShader>}
25230 */
25231 this.shaderCache_ = {};
25232
25233 /**
25234 * @private
25235 * @type {Object.<string, WebGLProgram>}
25236 */
25237 this.programCache_ = {};
25238
25239 /**
25240 * @private
25241 * @type {WebGLProgram}
25242 */
25243 this.currentProgram_ = null;
25244
25245 /**
25246 * @private
25247 * @type {WebGLFramebuffer}
25248 */
25249 this.hitDetectionFramebuffer_ = null;
25250
25251 /**
25252 * @private
25253 * @type {WebGLTexture}
25254 */
25255 this.hitDetectionTexture_ = null;
25256
25257 /**
25258 * @private
25259 * @type {WebGLRenderbuffer}
25260 */
25261 this.hitDetectionRenderbuffer_ = null;
25262
25263 /**
25264 * @type {boolean}
25265 */
25266 this.hasOESElementIndexUint = ol.array.includes(
25267 ol.WEBGL_EXTENSIONS, 'OES_element_index_uint');
25268
25269 // use the OES_element_index_uint extension if available
25270 if (this.hasOESElementIndexUint) {
25271 gl.getExtension('OES_element_index_uint');
25272 }
25273
25274 ol.events.listen(this.canvas_, ol.webgl.ContextEventType.LOST,
25275 this.handleWebGLContextLost, this);
25276 ol.events.listen(this.canvas_, ol.webgl.ContextEventType.RESTORED,
25277 this.handleWebGLContextRestored, this);
25278
25279 };
25280 ol.inherits(ol.webgl.Context, ol.Disposable);
25281
25282
25283 /**
25284 * Just bind the buffer if it's in the cache. Otherwise create
25285 * the WebGL buffer, bind it, populate it, and add an entry to
25286 * the cache.
25287 * @param {number} target Target.
25288 * @param {ol.webgl.Buffer} buf Buffer.
25289 */
25290 ol.webgl.Context.prototype.bindBuffer = function(target, buf) {
25291 var gl = this.getGL();
25292 var arr = buf.getArray();
25293 var bufferKey = String(ol.getUid(buf));
25294 if (bufferKey in this.bufferCache_) {
25295 var bufferCacheEntry = this.bufferCache_[bufferKey];
25296 gl.bindBuffer(target, bufferCacheEntry.buffer);
25297 } else {
25298 var buffer = gl.createBuffer();
25299 gl.bindBuffer(target, buffer);
25300 var /** @type {ArrayBufferView} */ arrayBuffer;
25301 if (target == ol.webgl.ARRAY_BUFFER) {
25302 arrayBuffer = new Float32Array(arr);
25303 } else if (target == ol.webgl.ELEMENT_ARRAY_BUFFER) {
25304 arrayBuffer = this.hasOESElementIndexUint ?
25305 new Uint32Array(arr) : new Uint16Array(arr);
25306 }
25307 gl.bufferData(target, arrayBuffer, buf.getUsage());
25308 this.bufferCache_[bufferKey] = {
25309 buf: buf,
25310 buffer: buffer
25311 };
25312 }
25313 };
25314
25315
25316 /**
25317 * @param {ol.webgl.Buffer} buf Buffer.
25318 */
25319 ol.webgl.Context.prototype.deleteBuffer = function(buf) {
25320 var gl = this.getGL();
25321 var bufferKey = String(ol.getUid(buf));
25322 var bufferCacheEntry = this.bufferCache_[bufferKey];
25323 if (!gl.isContextLost()) {
25324 gl.deleteBuffer(bufferCacheEntry.buffer);
25325 }
25326 delete this.bufferCache_[bufferKey];
25327 };
25328
25329
25330 /**
25331 * @inheritDoc
25332 */
25333 ol.webgl.Context.prototype.disposeInternal = function() {
25334 ol.events.unlistenAll(this.canvas_);
25335 var gl = this.getGL();
25336 if (!gl.isContextLost()) {
25337 var key;
25338 for (key in this.bufferCache_) {
25339 gl.deleteBuffer(this.bufferCache_[key].buffer);
25340 }
25341 for (key in this.programCache_) {
25342 gl.deleteProgram(this.programCache_[key]);
25343 }
25344 for (key in this.shaderCache_) {
25345 gl.deleteShader(this.shaderCache_[key]);
25346 }
25347 // delete objects for hit-detection
25348 gl.deleteFramebuffer(this.hitDetectionFramebuffer_);
25349 gl.deleteRenderbuffer(this.hitDetectionRenderbuffer_);
25350 gl.deleteTexture(this.hitDetectionTexture_);
25351 }
25352 };
25353
25354
25355 /**
25356 * @return {HTMLCanvasElement} Canvas.
25357 */
25358 ol.webgl.Context.prototype.getCanvas = function() {
25359 return this.canvas_;
25360 };
25361
25362
25363 /**
25364 * Get the WebGL rendering context
25365 * @return {WebGLRenderingContext} The rendering context.
25366 * @api
25367 */
25368 ol.webgl.Context.prototype.getGL = function() {
25369 return this.gl_;
25370 };
25371
25372
25373 /**
25374 * Get the frame buffer for hit detection.
25375 * @return {WebGLFramebuffer} The hit detection frame buffer.
25376 */
25377 ol.webgl.Context.prototype.getHitDetectionFramebuffer = function() {
25378 if (!this.hitDetectionFramebuffer_) {
25379 this.initHitDetectionFramebuffer_();
25380 }
25381 return this.hitDetectionFramebuffer_;
25382 };
25383
25384
25385 /**
25386 * Get shader from the cache if it's in the cache. Otherwise, create
25387 * the WebGL shader, compile it, and add entry to cache.
25388 * @param {ol.webgl.Shader} shaderObject Shader object.
25389 * @return {WebGLShader} Shader.
25390 */
25391 ol.webgl.Context.prototype.getShader = function(shaderObject) {
25392 var shaderKey = String(ol.getUid(shaderObject));
25393 if (shaderKey in this.shaderCache_) {
25394 return this.shaderCache_[shaderKey];
25395 } else {
25396 var gl = this.getGL();
25397 var shader = gl.createShader(shaderObject.getType());
25398 gl.shaderSource(shader, shaderObject.getSource());
25399 gl.compileShader(shader);
25400 this.shaderCache_[shaderKey] = shader;
25401 return shader;
25402 }
25403 };
25404
25405
25406 /**
25407 * Get the program from the cache if it's in the cache. Otherwise create
25408 * the WebGL program, attach the shaders to it, and add an entry to the
25409 * cache.
25410 * @param {ol.webgl.Fragment} fragmentShaderObject Fragment shader.
25411 * @param {ol.webgl.Vertex} vertexShaderObject Vertex shader.
25412 * @return {WebGLProgram} Program.
25413 */
25414 ol.webgl.Context.prototype.getProgram = function(
25415 fragmentShaderObject, vertexShaderObject) {
25416 var programKey =
25417 ol.getUid(fragmentShaderObject) + '/' + ol.getUid(vertexShaderObject);
25418 if (programKey in this.programCache_) {
25419 return this.programCache_[programKey];
25420 } else {
25421 var gl = this.getGL();
25422 var program = gl.createProgram();
25423 gl.attachShader(program, this.getShader(fragmentShaderObject));
25424 gl.attachShader(program, this.getShader(vertexShaderObject));
25425 gl.linkProgram(program);
25426 this.programCache_[programKey] = program;
25427 return program;
25428 }
25429 };
25430
25431
25432 /**
25433 * FIXME empy description for jsdoc
25434 */
25435 ol.webgl.Context.prototype.handleWebGLContextLost = function() {
25436 ol.obj.clear(this.bufferCache_);
25437 ol.obj.clear(this.shaderCache_);
25438 ol.obj.clear(this.programCache_);
25439 this.currentProgram_ = null;
25440 this.hitDetectionFramebuffer_ = null;
25441 this.hitDetectionTexture_ = null;
25442 this.hitDetectionRenderbuffer_ = null;
25443 };
25444
25445
25446 /**
25447 * FIXME empy description for jsdoc
25448 */
25449 ol.webgl.Context.prototype.handleWebGLContextRestored = function() {
25450 };
25451
25452
25453 /**
25454 * Creates a 1x1 pixel framebuffer for the hit-detection.
25455 * @private
25456 */
25457 ol.webgl.Context.prototype.initHitDetectionFramebuffer_ = function() {
25458 var gl = this.gl_;
25459 var framebuffer = gl.createFramebuffer();
25460 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
25461
25462 var texture = ol.webgl.Context.createEmptyTexture(gl, 1, 1);
25463 var renderbuffer = gl.createRenderbuffer();
25464 gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
25465 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 1, 1);
25466 gl.framebufferTexture2D(
25467 gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
25468 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT,
25469 gl.RENDERBUFFER, renderbuffer);
25470
25471 gl.bindTexture(gl.TEXTURE_2D, null);
25472 gl.bindRenderbuffer(gl.RENDERBUFFER, null);
25473 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
25474
25475 this.hitDetectionFramebuffer_ = framebuffer;
25476 this.hitDetectionTexture_ = texture;
25477 this.hitDetectionRenderbuffer_ = renderbuffer;
25478 };
25479
25480
25481 /**
25482 * Use a program. If the program is already in use, this will return `false`.
25483 * @param {WebGLProgram} program Program.
25484 * @return {boolean} Changed.
25485 * @api
25486 */
25487 ol.webgl.Context.prototype.useProgram = function(program) {
25488 if (program == this.currentProgram_) {
25489 return false;
25490 } else {
25491 var gl = this.getGL();
25492 gl.useProgram(program);
25493 this.currentProgram_ = program;
25494 return true;
25495 }
25496 };
25497
25498
25499 /**
25500 * @param {WebGLRenderingContext} gl WebGL rendering context.
25501 * @param {number=} opt_wrapS wrapS.
25502 * @param {number=} opt_wrapT wrapT.
25503 * @return {WebGLTexture} The texture.
25504 * @private
25505 */
25506 ol.webgl.Context.createTexture_ = function(gl, opt_wrapS, opt_wrapT) {
25507 var texture = gl.createTexture();
25508 gl.bindTexture(gl.TEXTURE_2D, texture);
25509 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
25510 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
25511
25512 if (opt_wrapS !== undefined) {
25513 gl.texParameteri(
25514 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_S, opt_wrapS);
25515 }
25516 if (opt_wrapT !== undefined) {
25517 gl.texParameteri(
25518 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_T, opt_wrapT);
25519 }
25520
25521 return texture;
25522 };
25523
25524
25525 /**
25526 * @param {WebGLRenderingContext} gl WebGL rendering context.
25527 * @param {number} width Width.
25528 * @param {number} height Height.
25529 * @param {number=} opt_wrapS wrapS.
25530 * @param {number=} opt_wrapT wrapT.
25531 * @return {WebGLTexture} The texture.
25532 */
25533 ol.webgl.Context.createEmptyTexture = function(
25534 gl, width, height, opt_wrapS, opt_wrapT) {
25535 var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
25536 gl.texImage2D(
25537 gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE,
25538 null);
25539
25540 return texture;
25541 };
25542
25543
25544 /**
25545 * @param {WebGLRenderingContext} gl WebGL rendering context.
25546 * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image.
25547 * @param {number=} opt_wrapS wrapS.
25548 * @param {number=} opt_wrapT wrapT.
25549 * @return {WebGLTexture} The texture.
25550 */
25551 ol.webgl.Context.createTexture = function(gl, image, opt_wrapS, opt_wrapT) {
25552 var texture = ol.webgl.Context.createTexture_(gl, opt_wrapS, opt_wrapT);
25553 gl.texImage2D(
25554 gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
25555
25556 return texture;
25557 };
25558
25559}
25560
25561goog.provide('ol.render.webgl.TextureReplay');
25562
25563goog.require('ol');
25564goog.require('ol.extent');
25565goog.require('ol.obj');
25566goog.require('ol.render.webgl.texturereplay.defaultshader');
25567goog.require('ol.render.webgl.Replay');
25568goog.require('ol.webgl');
25569goog.require('ol.webgl.Context');
25570
25571if (ol.ENABLE_WEBGL) {
25572
25573 /**
25574 * @constructor
25575 * @abstract
25576 * @extends {ol.render.webgl.Replay}
25577 * @param {number} tolerance Tolerance.
25578 * @param {ol.Extent} maxExtent Max extent.
25579 * @struct
25580 */
25581 ol.render.webgl.TextureReplay = function(tolerance, maxExtent) {
25582 ol.render.webgl.Replay.call(this, tolerance, maxExtent);
25583
25584 /**
25585 * @type {number|undefined}
25586 * @protected
25587 */
25588 this.anchorX = undefined;
25589
25590 /**
25591 * @type {number|undefined}
25592 * @protected
25593 */
25594 this.anchorY = undefined;
25595
25596 /**
25597 * @type {Array.<number>}
25598 * @protected
25599 */
25600 this.groupIndices = [];
25601
25602 /**
25603 * @type {Array.<number>}
25604 * @protected
25605 */
25606 this.hitDetectionGroupIndices = [];
25607
25608 /**
25609 * @type {number|undefined}
25610 * @protected
25611 */
25612 this.height = undefined;
25613
25614 /**
25615 * @type {number|undefined}
25616 * @protected
25617 */
25618 this.imageHeight = undefined;
25619
25620 /**
25621 * @type {number|undefined}
25622 * @protected
25623 */
25624 this.imageWidth = undefined;
25625
25626 /**
25627 * @protected
25628 * @type {ol.render.webgl.texturereplay.defaultshader.Locations}
25629 */
25630 this.defaultLocations = null;
25631
25632 /**
25633 * @protected
25634 * @type {number|undefined}
25635 */
25636 this.opacity = undefined;
25637
25638 /**
25639 * @type {number|undefined}
25640 * @protected
25641 */
25642 this.originX = undefined;
25643
25644 /**
25645 * @type {number|undefined}
25646 * @protected
25647 */
25648 this.originY = undefined;
25649
25650 /**
25651 * @protected
25652 * @type {boolean|undefined}
25653 */
25654 this.rotateWithView = undefined;
25655
25656 /**
25657 * @protected
25658 * @type {number|undefined}
25659 */
25660 this.rotation = undefined;
25661
25662 /**
25663 * @protected
25664 * @type {number|undefined}
25665 */
25666 this.scale = undefined;
25667
25668 /**
25669 * @type {number|undefined}
25670 * @protected
25671 */
25672 this.width = undefined;
25673 };
25674 ol.inherits(ol.render.webgl.TextureReplay, ol.render.webgl.Replay);
25675
25676
25677 /**
25678 * @inheritDoc
25679 */
25680 ol.render.webgl.TextureReplay.prototype.getDeleteResourcesFunction = function(context) {
25681 var verticesBuffer = this.verticesBuffer;
25682 var indicesBuffer = this.indicesBuffer;
25683 var textures = this.getTextures(true);
25684 var gl = context.getGL();
25685 return function() {
25686 if (!gl.isContextLost()) {
25687 var i, ii;
25688 for (i = 0, ii = textures.length; i < ii; ++i) {
25689 gl.deleteTexture(textures[i]);
25690 }
25691 }
25692 context.deleteBuffer(verticesBuffer);
25693 context.deleteBuffer(indicesBuffer);
25694 };
25695 };
25696
25697
25698 /**
25699 * @param {Array.<number>} flatCoordinates Flat coordinates.
25700 * @param {number} offset Offset.
25701 * @param {number} end End.
25702 * @param {number} stride Stride.
25703 * @return {number} My end.
25704 * @protected
25705 */
25706 ol.render.webgl.TextureReplay.prototype.drawCoordinates = function(flatCoordinates, offset, end, stride) {
25707 var anchorX = /** @type {number} */ (this.anchorX);
25708 var anchorY = /** @type {number} */ (this.anchorY);
25709 var height = /** @type {number} */ (this.height);
25710 var imageHeight = /** @type {number} */ (this.imageHeight);
25711 var imageWidth = /** @type {number} */ (this.imageWidth);
25712 var opacity = /** @type {number} */ (this.opacity);
25713 var originX = /** @type {number} */ (this.originX);
25714 var originY = /** @type {number} */ (this.originY);
25715 var rotateWithView = this.rotateWithView ? 1.0 : 0.0;
25716 // this.rotation_ is anti-clockwise, but rotation is clockwise
25717 var rotation = /** @type {number} */ (-this.rotation);
25718 var scale = /** @type {number} */ (this.scale);
25719 var width = /** @type {number} */ (this.width);
25720 var cos = Math.cos(rotation);
25721 var sin = Math.sin(rotation);
25722 var numIndices = this.indices.length;
25723 var numVertices = this.vertices.length;
25724 var i, n, offsetX, offsetY, x, y;
25725 for (i = offset; i < end; i += stride) {
25726 x = flatCoordinates[i] - this.origin[0];
25727 y = flatCoordinates[i + 1] - this.origin[1];
25728
25729 // There are 4 vertices per [x, y] point, one for each corner of the
25730 // rectangle we're going to draw. We'd use 1 vertex per [x, y] point if
25731 // WebGL supported Geometry Shaders (which can emit new vertices), but that
25732 // is not currently the case.
25733 //
25734 // And each vertex includes 8 values: the x and y coordinates, the x and
25735 // y offsets used to calculate the position of the corner, the u and
25736 // v texture coordinates for the corner, the opacity, and whether the
25737 // the image should be rotated with the view (rotateWithView).
25738
25739 n = numVertices / 8;
25740
25741 // bottom-left corner
25742 offsetX = -scale * anchorX;
25743 offsetY = -scale * (height - anchorY);
25744 this.vertices[numVertices++] = x;
25745 this.vertices[numVertices++] = y;
25746 this.vertices[numVertices++] = offsetX * cos - offsetY * sin;
25747 this.vertices[numVertices++] = offsetX * sin + offsetY * cos;
25748 this.vertices[numVertices++] = originX / imageWidth;
25749 this.vertices[numVertices++] = (originY + height) / imageHeight;
25750 this.vertices[numVertices++] = opacity;
25751 this.vertices[numVertices++] = rotateWithView;
25752
25753 // bottom-right corner
25754 offsetX = scale * (width - anchorX);
25755 offsetY = -scale * (height - anchorY);
25756 this.vertices[numVertices++] = x;
25757 this.vertices[numVertices++] = y;
25758 this.vertices[numVertices++] = offsetX * cos - offsetY * sin;
25759 this.vertices[numVertices++] = offsetX * sin + offsetY * cos;
25760 this.vertices[numVertices++] = (originX + width) / imageWidth;
25761 this.vertices[numVertices++] = (originY + height) / imageHeight;
25762 this.vertices[numVertices++] = opacity;
25763 this.vertices[numVertices++] = rotateWithView;
25764
25765 // top-right corner
25766 offsetX = scale * (width - anchorX);
25767 offsetY = scale * anchorY;
25768 this.vertices[numVertices++] = x;
25769 this.vertices[numVertices++] = y;
25770 this.vertices[numVertices++] = offsetX * cos - offsetY * sin;
25771 this.vertices[numVertices++] = offsetX * sin + offsetY * cos;
25772 this.vertices[numVertices++] = (originX + width) / imageWidth;
25773 this.vertices[numVertices++] = originY / imageHeight;
25774 this.vertices[numVertices++] = opacity;
25775 this.vertices[numVertices++] = rotateWithView;
25776
25777 // top-left corner
25778 offsetX = -scale * anchorX;
25779 offsetY = scale * anchorY;
25780 this.vertices[numVertices++] = x;
25781 this.vertices[numVertices++] = y;
25782 this.vertices[numVertices++] = offsetX * cos - offsetY * sin;
25783 this.vertices[numVertices++] = offsetX * sin + offsetY * cos;
25784 this.vertices[numVertices++] = originX / imageWidth;
25785 this.vertices[numVertices++] = originY / imageHeight;
25786 this.vertices[numVertices++] = opacity;
25787 this.vertices[numVertices++] = rotateWithView;
25788
25789 this.indices[numIndices++] = n;
25790 this.indices[numIndices++] = n + 1;
25791 this.indices[numIndices++] = n + 2;
25792 this.indices[numIndices++] = n;
25793 this.indices[numIndices++] = n + 2;
25794 this.indices[numIndices++] = n + 3;
25795 }
25796
25797 return numVertices;
25798 };
25799
25800
25801 /**
25802 * @protected
25803 * @param {Array.<WebGLTexture>} textures Textures.
25804 * @param {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>} images
25805 * Images.
25806 * @param {Object.<string, WebGLTexture>} texturePerImage Texture cache.
25807 * @param {WebGLRenderingContext} gl Gl.
25808 */
25809 ol.render.webgl.TextureReplay.prototype.createTextures = function(textures, images, texturePerImage, gl) {
25810 var texture, image, uid, i;
25811 var ii = images.length;
25812 for (i = 0; i < ii; ++i) {
25813 image = images[i];
25814
25815 uid = ol.getUid(image).toString();
25816 if (uid in texturePerImage) {
25817 texture = texturePerImage[uid];
25818 } else {
25819 texture = ol.webgl.Context.createTexture(
25820 gl, image, ol.webgl.CLAMP_TO_EDGE, ol.webgl.CLAMP_TO_EDGE);
25821 texturePerImage[uid] = texture;
25822 }
25823 textures[i] = texture;
25824 }
25825 };
25826
25827
25828 /**
25829 * @inheritDoc
25830 */
25831 ol.render.webgl.TextureReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {
25832 // get the program
25833 var fragmentShader = ol.render.webgl.texturereplay.defaultshader.fragment;
25834 var vertexShader = ol.render.webgl.texturereplay.defaultshader.vertex;
25835 var program = context.getProgram(fragmentShader, vertexShader);
25836
25837 // get the locations
25838 var locations;
25839 if (!this.defaultLocations) {
25840 // eslint-disable-next-line openlayers-internal/no-missing-requires
25841 locations = new ol.render.webgl.texturereplay.defaultshader.Locations(gl, program);
25842 this.defaultLocations = locations;
25843 } else {
25844 locations = this.defaultLocations;
25845 }
25846
25847 // use the program (FIXME: use the return value)
25848 context.useProgram(program);
25849
25850 // enable the vertex attrib arrays
25851 gl.enableVertexAttribArray(locations.a_position);
25852 gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,
25853 false, 32, 0);
25854
25855 gl.enableVertexAttribArray(locations.a_offsets);
25856 gl.vertexAttribPointer(locations.a_offsets, 2, ol.webgl.FLOAT,
25857 false, 32, 8);
25858
25859 gl.enableVertexAttribArray(locations.a_texCoord);
25860 gl.vertexAttribPointer(locations.a_texCoord, 2, ol.webgl.FLOAT,
25861 false, 32, 16);
25862
25863 gl.enableVertexAttribArray(locations.a_opacity);
25864 gl.vertexAttribPointer(locations.a_opacity, 1, ol.webgl.FLOAT,
25865 false, 32, 24);
25866
25867 gl.enableVertexAttribArray(locations.a_rotateWithView);
25868 gl.vertexAttribPointer(locations.a_rotateWithView, 1, ol.webgl.FLOAT,
25869 false, 32, 28);
25870
25871 return locations;
25872 };
25873
25874
25875 /**
25876 * @inheritDoc
25877 */
25878 ol.render.webgl.TextureReplay.prototype.shutDownProgram = function(gl, locations) {
25879 gl.disableVertexAttribArray(locations.a_position);
25880 gl.disableVertexAttribArray(locations.a_offsets);
25881 gl.disableVertexAttribArray(locations.a_texCoord);
25882 gl.disableVertexAttribArray(locations.a_opacity);
25883 gl.disableVertexAttribArray(locations.a_rotateWithView);
25884 };
25885
25886
25887 /**
25888 * @inheritDoc
25889 */
25890 ol.render.webgl.TextureReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {
25891 var textures = hitDetection ? this.getHitDetectionTextures() : this.getTextures();
25892 var groupIndices = hitDetection ? this.hitDetectionGroupIndices : this.groupIndices;
25893
25894 if (!ol.obj.isEmpty(skippedFeaturesHash)) {
25895 this.drawReplaySkipping(
25896 gl, context, skippedFeaturesHash, textures, groupIndices);
25897 } else {
25898 var i, ii, start;
25899 for (i = 0, ii = textures.length, start = 0; i < ii; ++i) {
25900 gl.bindTexture(ol.webgl.TEXTURE_2D, textures[i]);
25901 var end = groupIndices[i];
25902 this.drawElements(gl, context, start, end);
25903 start = end;
25904 }
25905 }
25906 };
25907
25908
25909 /**
25910 * Draw the replay while paying attention to skipped features.
25911 *
25912 * This functions creates groups of features that can be drawn to together,
25913 * so that the number of `drawElements` calls is minimized.
25914 *
25915 * For example given the following texture groups:
25916 *
25917 * Group 1: A B C
25918 * Group 2: D [E] F G
25919 *
25920 * If feature E should be skipped, the following `drawElements` calls will be
25921 * made:
25922 *
25923 * drawElements with feature A, B and C
25924 * drawElements with feature D
25925 * drawElements with feature F and G
25926 *
25927 * @protected
25928 * @param {WebGLRenderingContext} gl gl.
25929 * @param {ol.webgl.Context} context Context.
25930 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
25931 * to skip.
25932 * @param {Array.<WebGLTexture>} textures Textures.
25933 * @param {Array.<number>} groupIndices Texture group indices.
25934 */
25935 ol.render.webgl.TextureReplay.prototype.drawReplaySkipping = function(gl, context, skippedFeaturesHash, textures,
25936 groupIndices) {
25937 var featureIndex = 0;
25938
25939 var i, ii;
25940 for (i = 0, ii = textures.length; i < ii; ++i) {
25941 gl.bindTexture(ol.webgl.TEXTURE_2D, textures[i]);
25942 var groupStart = (i > 0) ? groupIndices[i - 1] : 0;
25943 var groupEnd = groupIndices[i];
25944
25945 var start = groupStart;
25946 var end = groupStart;
25947 while (featureIndex < this.startIndices.length &&
25948 this.startIndices[featureIndex] <= groupEnd) {
25949 var feature = this.startIndicesFeature[featureIndex];
25950
25951 var featureUid = ol.getUid(feature).toString();
25952 if (skippedFeaturesHash[featureUid] !== undefined) {
25953 // feature should be skipped
25954 if (start !== end) {
25955 // draw the features so far
25956 this.drawElements(gl, context, start, end);
25957 }
25958 // continue with the next feature
25959 start = (featureIndex === this.startIndices.length - 1) ?
25960 groupEnd : this.startIndices[featureIndex + 1];
25961 end = start;
25962 } else {
25963 // the feature is not skipped, augment the end index
25964 end = (featureIndex === this.startIndices.length - 1) ?
25965 groupEnd : this.startIndices[featureIndex + 1];
25966 }
25967 featureIndex++;
25968 }
25969
25970 if (start !== end) {
25971 // draw the remaining features (in case there was no skipped feature
25972 // in this texture group, all features of a group are drawn together)
25973 this.drawElements(gl, context, start, end);
25974 }
25975 }
25976 };
25977
25978
25979 /**
25980 * @inheritDoc
25981 */
25982 ol.render.webgl.TextureReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,
25983 featureCallback, opt_hitExtent) {
25984 var i, groupStart, start, end, feature, featureUid;
25985 var featureIndex = this.startIndices.length - 1;
25986 var hitDetectionTextures = this.getHitDetectionTextures();
25987 for (i = hitDetectionTextures.length - 1; i >= 0; --i) {
25988 gl.bindTexture(ol.webgl.TEXTURE_2D, hitDetectionTextures[i]);
25989 groupStart = (i > 0) ? this.hitDetectionGroupIndices[i - 1] : 0;
25990 end = this.hitDetectionGroupIndices[i];
25991
25992 // draw all features for this texture group
25993 while (featureIndex >= 0 &&
25994 this.startIndices[featureIndex] >= groupStart) {
25995 start = this.startIndices[featureIndex];
25996 feature = this.startIndicesFeature[featureIndex];
25997 featureUid = ol.getUid(feature).toString();
25998
25999 if (skippedFeaturesHash[featureUid] === undefined &&
26000 feature.getGeometry() &&
26001 (opt_hitExtent === undefined || ol.extent.intersects(
26002 /** @type {Array<number>} */ (opt_hitExtent),
26003 feature.getGeometry().getExtent()))) {
26004 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
26005 this.drawElements(gl, context, start, end);
26006
26007 var result = featureCallback(feature);
26008 if (result) {
26009 return result;
26010 }
26011 }
26012
26013 end = start;
26014 featureIndex--;
26015 }
26016 }
26017 return undefined;
26018 };
26019
26020
26021 /**
26022 * @inheritDoc
26023 */
26024 ol.render.webgl.TextureReplay.prototype.finish = function(context) {
26025 this.anchorX = undefined;
26026 this.anchorY = undefined;
26027 this.height = undefined;
26028 this.imageHeight = undefined;
26029 this.imageWidth = undefined;
26030 this.indices = null;
26031 this.opacity = undefined;
26032 this.originX = undefined;
26033 this.originY = undefined;
26034 this.rotateWithView = undefined;
26035 this.rotation = undefined;
26036 this.scale = undefined;
26037 this.vertices = null;
26038 this.width = undefined;
26039 };
26040
26041
26042 /**
26043 * @abstract
26044 * @protected
26045 * @param {boolean=} opt_all Return hit detection textures with regular ones.
26046 * @returns {Array.<WebGLTexture>} Textures.
26047 */
26048 ol.render.webgl.TextureReplay.prototype.getTextures = function(opt_all) {};
26049
26050
26051 /**
26052 * @abstract
26053 * @protected
26054 * @returns {Array.<WebGLTexture>} Textures.
26055 */
26056 ol.render.webgl.TextureReplay.prototype.getHitDetectionTextures = function() {};
26057}
26058
26059goog.provide('ol.render.webgl.ImageReplay');
26060
26061goog.require('ol');
26062goog.require('ol.render.webgl.TextureReplay');
26063goog.require('ol.webgl.Buffer');
26064
26065
26066if (ol.ENABLE_WEBGL) {
26067
26068 /**
26069 * @constructor
26070 * @extends {ol.render.webgl.TextureReplay}
26071 * @param {number} tolerance Tolerance.
26072 * @param {ol.Extent} maxExtent Max extent.
26073 * @struct
26074 */
26075 ol.render.webgl.ImageReplay = function(tolerance, maxExtent) {
26076 ol.render.webgl.TextureReplay.call(this, tolerance, maxExtent);
26077
26078 /**
26079 * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}
26080 * @protected
26081 */
26082 this.images_ = [];
26083
26084 /**
26085 * @type {Array.<HTMLCanvasElement|HTMLImageElement|HTMLVideoElement>}
26086 * @protected
26087 */
26088 this.hitDetectionImages_ = [];
26089
26090 /**
26091 * @type {Array.<WebGLTexture>}
26092 * @private
26093 */
26094 this.textures_ = [];
26095
26096 /**
26097 * @type {Array.<WebGLTexture>}
26098 * @private
26099 */
26100 this.hitDetectionTextures_ = [];
26101
26102 };
26103 ol.inherits(ol.render.webgl.ImageReplay, ol.render.webgl.TextureReplay);
26104
26105
26106 /**
26107 * @inheritDoc
26108 */
26109 ol.render.webgl.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {
26110 this.startIndices.push(this.indices.length);
26111 this.startIndicesFeature.push(feature);
26112 var flatCoordinates = multiPointGeometry.getFlatCoordinates();
26113 var stride = multiPointGeometry.getStride();
26114 this.drawCoordinates(
26115 flatCoordinates, 0, flatCoordinates.length, stride);
26116 };
26117
26118
26119 /**
26120 * @inheritDoc
26121 */
26122 ol.render.webgl.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {
26123 this.startIndices.push(this.indices.length);
26124 this.startIndicesFeature.push(feature);
26125 var flatCoordinates = pointGeometry.getFlatCoordinates();
26126 var stride = pointGeometry.getStride();
26127 this.drawCoordinates(
26128 flatCoordinates, 0, flatCoordinates.length, stride);
26129 };
26130
26131
26132 /**
26133 * @inheritDoc
26134 */
26135 ol.render.webgl.ImageReplay.prototype.finish = function(context) {
26136 var gl = context.getGL();
26137
26138 this.groupIndices.push(this.indices.length);
26139 this.hitDetectionGroupIndices.push(this.indices.length);
26140
26141 // create, bind, and populate the vertices buffer
26142 this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
26143
26144 var indices = this.indices;
26145
26146 // create, bind, and populate the indices buffer
26147 this.indicesBuffer = new ol.webgl.Buffer(indices);
26148
26149 // create textures
26150 /** @type {Object.<string, WebGLTexture>} */
26151 var texturePerImage = {};
26152
26153 this.createTextures(this.textures_, this.images_, texturePerImage, gl);
26154
26155 this.createTextures(this.hitDetectionTextures_, this.hitDetectionImages_,
26156 texturePerImage, gl);
26157
26158 this.images_ = null;
26159 this.hitDetectionImages_ = null;
26160 ol.render.webgl.TextureReplay.prototype.finish.call(this, context);
26161 };
26162
26163
26164 /**
26165 * @inheritDoc
26166 */
26167 ol.render.webgl.ImageReplay.prototype.setImageStyle = function(imageStyle) {
26168 var anchor = imageStyle.getAnchor();
26169 var image = imageStyle.getImage(1);
26170 var imageSize = imageStyle.getImageSize();
26171 var hitDetectionImage = imageStyle.getHitDetectionImage(1);
26172 var opacity = imageStyle.getOpacity();
26173 var origin = imageStyle.getOrigin();
26174 var rotateWithView = imageStyle.getRotateWithView();
26175 var rotation = imageStyle.getRotation();
26176 var size = imageStyle.getSize();
26177 var scale = imageStyle.getScale();
26178
26179 var currentImage;
26180 if (this.images_.length === 0) {
26181 this.images_.push(image);
26182 } else {
26183 currentImage = this.images_[this.images_.length - 1];
26184 if (ol.getUid(currentImage) != ol.getUid(image)) {
26185 this.groupIndices.push(this.indices.length);
26186 this.images_.push(image);
26187 }
26188 }
26189
26190 if (this.hitDetectionImages_.length === 0) {
26191 this.hitDetectionImages_.push(hitDetectionImage);
26192 } else {
26193 currentImage =
26194 this.hitDetectionImages_[this.hitDetectionImages_.length - 1];
26195 if (ol.getUid(currentImage) != ol.getUid(hitDetectionImage)) {
26196 this.hitDetectionGroupIndices.push(this.indices.length);
26197 this.hitDetectionImages_.push(hitDetectionImage);
26198 }
26199 }
26200
26201 this.anchorX = anchor[0];
26202 this.anchorY = anchor[1];
26203 this.height = size[1];
26204 this.imageHeight = imageSize[1];
26205 this.imageWidth = imageSize[0];
26206 this.opacity = opacity;
26207 this.originX = origin[0];
26208 this.originY = origin[1];
26209 this.rotation = rotation;
26210 this.rotateWithView = rotateWithView;
26211 this.scale = scale;
26212 this.width = size[0];
26213 };
26214
26215
26216 /**
26217 * @inheritDoc
26218 */
26219 ol.render.webgl.ImageReplay.prototype.getTextures = function(opt_all) {
26220 return opt_all ? this.textures_.concat(this.hitDetectionTextures_) : this.textures_;
26221 };
26222
26223
26224 /**
26225 * @inheritDoc
26226 */
26227 ol.render.webgl.ImageReplay.prototype.getHitDetectionTextures = function() {
26228 return this.hitDetectionTextures_;
26229 };
26230
26231}
26232
26233goog.provide('ol.geom.flat.topology');
26234
26235goog.require('ol.geom.flat.area');
26236
26237/**
26238 * Check if the linestring is a boundary.
26239 * @param {Array.<number>} flatCoordinates Flat coordinates.
26240 * @param {number} offset Offset.
26241 * @param {number} end End.
26242 * @param {number} stride Stride.
26243 * @return {boolean} The linestring is a boundary.
26244 */
26245ol.geom.flat.topology.lineStringIsClosed = function(flatCoordinates, offset, end, stride) {
26246 var lastCoord = end - stride;
26247 if (flatCoordinates[offset] === flatCoordinates[lastCoord] &&
26248 flatCoordinates[offset + 1] === flatCoordinates[lastCoord + 1] && (end - offset) / stride > 3) {
26249 return !!ol.geom.flat.area.linearRing(flatCoordinates, offset, end, stride);
26250 }
26251 return false;
26252};
26253
26254// This file is automatically generated, do not edit
26255/* eslint openlayers-internal/no-missing-requires: 0 */
26256goog.provide('ol.render.webgl.linestringreplay.defaultshader');
26257
26258goog.require('ol');
26259goog.require('ol.webgl.Fragment');
26260goog.require('ol.webgl.Vertex');
26261
26262if (ol.ENABLE_WEBGL) {
26263
26264 /**
26265 * @constructor
26266 * @extends {ol.webgl.Fragment}
26267 * @struct
26268 */
26269 ol.render.webgl.linestringreplay.defaultshader.Fragment = function() {
26270 ol.webgl.Fragment.call(this, ol.render.webgl.linestringreplay.defaultshader.Fragment.SOURCE);
26271 };
26272 ol.inherits(ol.render.webgl.linestringreplay.defaultshader.Fragment, ol.webgl.Fragment);
26273
26274
26275 /**
26276 * @const
26277 * @type {string}
26278 */
26279 ol.render.webgl.linestringreplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying float v_round;\nvarying vec2 v_roundVertex;\nvarying float v_halfWidth;\n\n\n\nuniform float u_opacity;\nuniform vec4 u_color;\nuniform vec2 u_size;\nuniform float u_pixelRatio;\n\nvoid main(void) {\n if (v_round > 0.0) {\n vec2 windowCoords = vec2((v_roundVertex.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,\n (v_roundVertex.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);\n if (length(windowCoords - gl_FragCoord.xy) > v_halfWidth * u_pixelRatio) {\n discard;\n }\n }\n gl_FragColor = u_color;\n float alpha = u_color.a * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n';
26280
26281
26282 /**
26283 * @const
26284 * @type {string}
26285 */
26286 ol.render.webgl.linestringreplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying float a;varying vec2 b;varying float c;uniform float m;uniform vec4 n;uniform vec2 o;uniform float p;void main(void){if(a>0.0){vec2 windowCoords=vec2((b.x+1.0)/2.0*o.x*p,(b.y+1.0)/2.0*o.y*p);if(length(windowCoords-gl_FragCoord.xy)>c*p){discard;}} gl_FragColor=n;float alpha=n.a*m;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';
26287
26288
26289 /**
26290 * @const
26291 * @type {string}
26292 */
26293 ol.render.webgl.linestringreplay.defaultshader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
26294 ol.render.webgl.linestringreplay.defaultshader.Fragment.DEBUG_SOURCE :
26295 ol.render.webgl.linestringreplay.defaultshader.Fragment.OPTIMIZED_SOURCE;
26296
26297
26298 ol.render.webgl.linestringreplay.defaultshader.fragment = new ol.render.webgl.linestringreplay.defaultshader.Fragment();
26299
26300
26301 /**
26302 * @constructor
26303 * @extends {ol.webgl.Vertex}
26304 * @struct
26305 */
26306 ol.render.webgl.linestringreplay.defaultshader.Vertex = function() {
26307 ol.webgl.Vertex.call(this, ol.render.webgl.linestringreplay.defaultshader.Vertex.SOURCE);
26308 };
26309 ol.inherits(ol.render.webgl.linestringreplay.defaultshader.Vertex, ol.webgl.Vertex);
26310
26311
26312 /**
26313 * @const
26314 * @type {string}
26315 */
26316 ol.render.webgl.linestringreplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying float v_round;\nvarying vec2 v_roundVertex;\nvarying float v_halfWidth;\n\n\nattribute vec2 a_lastPos;\nattribute vec2 a_position;\nattribute vec2 a_nextPos;\nattribute float a_direction;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_lineWidth;\nuniform float u_miterLimit;\n\nbool nearlyEquals(in float value, in float ref) {\n float epsilon = 0.000000000001;\n return value >= ref - epsilon && value <= ref + epsilon;\n}\n\nvoid alongNormal(out vec2 offset, in vec2 nextP, in float turnDir, in float direction) {\n vec2 dirVect = nextP - a_position;\n vec2 normal = normalize(vec2(-turnDir * dirVect.y, turnDir * dirVect.x));\n offset = u_lineWidth / 2.0 * normal * direction;\n}\n\nvoid miterUp(out vec2 offset, out float round, in bool isRound, in float direction) {\n float halfWidth = u_lineWidth / 2.0;\n vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\n vec2 normal = vec2(-tangent.y, tangent.x);\n vec2 dirVect = a_nextPos - a_position;\n vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\n float miterLength = abs(halfWidth / dot(normal, tmpNormal));\n offset = normal * direction * miterLength;\n round = 0.0;\n if (isRound) {\n round = 1.0;\n } else if (miterLength > u_miterLimit + u_lineWidth) {\n offset = halfWidth * tmpNormal * direction;\n }\n}\n\nbool miterDown(out vec2 offset, in vec4 projPos, in mat4 offsetMatrix, in float direction) {\n bool degenerate = false;\n vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\n vec2 normal = vec2(-tangent.y, tangent.x);\n vec2 dirVect = a_lastPos - a_position;\n vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\n vec2 longOffset, shortOffset, longVertex;\n vec4 shortProjVertex;\n float halfWidth = u_lineWidth / 2.0;\n if (length(a_nextPos - a_position) > length(a_lastPos - a_position)) {\n longOffset = tmpNormal * direction * halfWidth;\n shortOffset = normalize(vec2(dirVect.y, -dirVect.x)) * direction * halfWidth;\n longVertex = a_nextPos;\n shortProjVertex = u_projectionMatrix * vec4(a_lastPos, 0.0, 1.0);\n } else {\n shortOffset = tmpNormal * direction * halfWidth;\n longOffset = normalize(vec2(dirVect.y, -dirVect.x)) * direction * halfWidth;\n longVertex = a_lastPos;\n shortProjVertex = u_projectionMatrix * vec4(a_nextPos, 0.0, 1.0);\n }\n //Intersection algorithm based on theory by Paul Bourke (http://paulbourke.net/geometry/pointlineplane/).\n vec4 p1 = u_projectionMatrix * vec4(longVertex, 0.0, 1.0) + offsetMatrix * vec4(longOffset, 0.0, 0.0);\n vec4 p2 = projPos + offsetMatrix * vec4(longOffset, 0.0, 0.0);\n vec4 p3 = shortProjVertex + offsetMatrix * vec4(-shortOffset, 0.0, 0.0);\n vec4 p4 = shortProjVertex + offsetMatrix * vec4(shortOffset, 0.0, 0.0);\n float denom = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y);\n float firstU = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)) / denom;\n float secondU = ((p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x)) / denom;\n float epsilon = 0.000000000001;\n if (firstU > epsilon && firstU < 1.0 - epsilon && secondU > epsilon && secondU < 1.0 - epsilon) {\n shortProjVertex.x = p1.x + firstU * (p2.x - p1.x);\n shortProjVertex.y = p1.y + firstU * (p2.y - p1.y);\n offset = shortProjVertex.xy;\n degenerate = true;\n } else {\n float miterLength = abs(halfWidth / dot(normal, tmpNormal));\n offset = normal * direction * miterLength;\n }\n return degenerate;\n}\n\nvoid squareCap(out vec2 offset, out float round, in bool isRound, in vec2 nextP,\n in float turnDir, in float direction) {\n round = 0.0;\n vec2 dirVect = a_position - nextP;\n vec2 firstNormal = normalize(dirVect);\n vec2 secondNormal = vec2(turnDir * firstNormal.y * direction, -turnDir * firstNormal.x * direction);\n vec2 hypotenuse = normalize(firstNormal - secondNormal);\n vec2 normal = vec2(turnDir * hypotenuse.y * direction, -turnDir * hypotenuse.x * direction);\n float length = sqrt(v_halfWidth * v_halfWidth * 2.0);\n offset = normal * length;\n if (isRound) {\n round = 1.0;\n }\n}\n\nvoid main(void) {\n bool degenerate = false;\n float direction = float(sign(a_direction));\n mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n vec2 offset;\n vec4 projPos = u_projectionMatrix * vec4(a_position, 0.0, 1.0);\n bool round = nearlyEquals(mod(a_direction, 2.0), 0.0);\n\n v_round = 0.0;\n v_halfWidth = u_lineWidth / 2.0;\n v_roundVertex = projPos.xy;\n\n if (nearlyEquals(mod(a_direction, 3.0), 0.0) || nearlyEquals(mod(a_direction, 17.0), 0.0)) {\n alongNormal(offset, a_nextPos, 1.0, direction);\n } else if (nearlyEquals(mod(a_direction, 5.0), 0.0) || nearlyEquals(mod(a_direction, 13.0), 0.0)) {\n alongNormal(offset, a_lastPos, -1.0, direction);\n } else if (nearlyEquals(mod(a_direction, 23.0), 0.0)) {\n miterUp(offset, v_round, round, direction);\n } else if (nearlyEquals(mod(a_direction, 19.0), 0.0)) {\n degenerate = miterDown(offset, projPos, offsetMatrix, direction);\n } else if (nearlyEquals(mod(a_direction, 7.0), 0.0)) {\n squareCap(offset, v_round, round, a_nextPos, 1.0, direction);\n } else if (nearlyEquals(mod(a_direction, 11.0), 0.0)) {\n squareCap(offset, v_round, round, a_lastPos, -1.0, direction);\n }\n if (!degenerate) {\n vec4 offsets = offsetMatrix * vec4(offset, 0.0, 0.0);\n gl_Position = projPos + offsets;\n } else {\n gl_Position = vec4(offset, 0.0, 1.0);\n }\n}\n\n\n';
26317
26318
26319 /**
26320 * @const
26321 * @type {string}
26322 */
26323 ol.render.webgl.linestringreplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying float a;varying vec2 b;varying float c;attribute vec2 d;attribute vec2 e;attribute vec2 f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;bool nearlyEquals(in float value,in float ref){float epsilon=0.000000000001;return value>=ref-epsilon&&value<=ref+epsilon;}void alongNormal(out vec2 offset,in vec2 nextP,in float turnDir,in float direction){vec2 dirVect=nextP-e;vec2 normal=normalize(vec2(-turnDir*dirVect.y,turnDir*dirVect.x));offset=k/2.0*normal*direction;}void miterUp(out vec2 offset,out float round,in bool isRound,in float direction){float halfWidth=k/2.0;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=f-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;round=0.0;if(isRound){round=1.0;}else if(miterLength>l+k){offset=halfWidth*tmpNormal*direction;}} bool miterDown(out vec2 offset,in vec4 projPos,in mat4 offsetMatrix,in float direction){bool degenerate=false;vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(-tangent.y,tangent.x);vec2 dirVect=d-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));vec2 longOffset,shortOffset,longVertex;vec4 shortProjVertex;float halfWidth=k/2.0;if(length(f-e)>length(d-e)){longOffset=tmpNormal*direction*halfWidth;shortOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=f;shortProjVertex=h*vec4(d,0.0,1.0);}else{shortOffset=tmpNormal*direction*halfWidth;longOffset=normalize(vec2(dirVect.y,-dirVect.x))*direction*halfWidth;longVertex=d;shortProjVertex=h*vec4(f,0.0,1.0);}vec4 p1=h*vec4(longVertex,0.0,1.0)+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p2=projPos+offsetMatrix*vec4(longOffset,0.0,0.0);vec4 p3=shortProjVertex+offsetMatrix*vec4(-shortOffset,0.0,0.0);vec4 p4=shortProjVertex+offsetMatrix*vec4(shortOffset,0.0,0.0);float denom=(p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y);float firstU=((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/denom;float secondU=((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/denom;float epsilon=0.000000000001;if(firstU>epsilon&&firstU<1.0-epsilon&&secondU>epsilon&&secondU<1.0-epsilon){shortProjVertex.x=p1.x+firstU*(p2.x-p1.x);shortProjVertex.y=p1.y+firstU*(p2.y-p1.y);offset=shortProjVertex.xy;degenerate=true;}else{float miterLength=abs(halfWidth/dot(normal,tmpNormal));offset=normal*direction*miterLength;}return degenerate;}void squareCap(out vec2 offset,out float round,in bool isRound,in vec2 nextP,in float turnDir,in float direction){round=0.0;vec2 dirVect=e-nextP;vec2 firstNormal=normalize(dirVect);vec2 secondNormal=vec2(turnDir*firstNormal.y*direction,-turnDir*firstNormal.x*direction);vec2 hypotenuse=normalize(firstNormal-secondNormal);vec2 normal=vec2(turnDir*hypotenuse.y*direction,-turnDir*hypotenuse.x*direction);float length=sqrt(c*c*2.0);offset=normal*length;if(isRound){round=1.0;}} void main(void){bool degenerate=false;float direction=float(sign(g));mat4 offsetMatrix=i*j;vec2 offset;vec4 projPos=h*vec4(e,0.0,1.0);bool round=nearlyEquals(mod(g,2.0),0.0);a=0.0;c=k/2.0;b=projPos.xy;if(nearlyEquals(mod(g,3.0),0.0)||nearlyEquals(mod(g,17.0),0.0)){alongNormal(offset,f,1.0,direction);}else if(nearlyEquals(mod(g,5.0),0.0)||nearlyEquals(mod(g,13.0),0.0)){alongNormal(offset,d,-1.0,direction);}else if(nearlyEquals(mod(g,23.0),0.0)){miterUp(offset,a,round,direction);}else if(nearlyEquals(mod(g,19.0),0.0)){degenerate=miterDown(offset,projPos,offsetMatrix,direction);}else if(nearlyEquals(mod(g,7.0),0.0)){squareCap(offset,a,round,f,1.0,direction);}else if(nearlyEquals(mod(g,11.0),0.0)){squareCap(offset,a,round,d,-1.0,direction);}if(!degenerate){vec4 offsets=offsetMatrix*vec4(offset,0.0,0.0);gl_Position=projPos+offsets;}else{gl_Position=vec4(offset,0.0,1.0);}}';
26324
26325
26326 /**
26327 * @const
26328 * @type {string}
26329 */
26330 ol.render.webgl.linestringreplay.defaultshader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
26331 ol.render.webgl.linestringreplay.defaultshader.Vertex.DEBUG_SOURCE :
26332 ol.render.webgl.linestringreplay.defaultshader.Vertex.OPTIMIZED_SOURCE;
26333
26334
26335 ol.render.webgl.linestringreplay.defaultshader.vertex = new ol.render.webgl.linestringreplay.defaultshader.Vertex();
26336
26337
26338 /**
26339 * @constructor
26340 * @param {WebGLRenderingContext} gl GL.
26341 * @param {WebGLProgram} program Program.
26342 * @struct
26343 */
26344 ol.render.webgl.linestringreplay.defaultshader.Locations = function(gl, program) {
26345
26346 /**
26347 * @type {WebGLUniformLocation}
26348 */
26349 this.u_color = gl.getUniformLocation(
26350 program, ol.DEBUG_WEBGL ? 'u_color' : 'n');
26351
26352 /**
26353 * @type {WebGLUniformLocation}
26354 */
26355 this.u_lineWidth = gl.getUniformLocation(
26356 program, ol.DEBUG_WEBGL ? 'u_lineWidth' : 'k');
26357
26358 /**
26359 * @type {WebGLUniformLocation}
26360 */
26361 this.u_miterLimit = gl.getUniformLocation(
26362 program, ol.DEBUG_WEBGL ? 'u_miterLimit' : 'l');
26363
26364 /**
26365 * @type {WebGLUniformLocation}
26366 */
26367 this.u_offsetRotateMatrix = gl.getUniformLocation(
26368 program, ol.DEBUG_WEBGL ? 'u_offsetRotateMatrix' : 'j');
26369
26370 /**
26371 * @type {WebGLUniformLocation}
26372 */
26373 this.u_offsetScaleMatrix = gl.getUniformLocation(
26374 program, ol.DEBUG_WEBGL ? 'u_offsetScaleMatrix' : 'i');
26375
26376 /**
26377 * @type {WebGLUniformLocation}
26378 */
26379 this.u_opacity = gl.getUniformLocation(
26380 program, ol.DEBUG_WEBGL ? 'u_opacity' : 'm');
26381
26382 /**
26383 * @type {WebGLUniformLocation}
26384 */
26385 this.u_pixelRatio = gl.getUniformLocation(
26386 program, ol.DEBUG_WEBGL ? 'u_pixelRatio' : 'p');
26387
26388 /**
26389 * @type {WebGLUniformLocation}
26390 */
26391 this.u_projectionMatrix = gl.getUniformLocation(
26392 program, ol.DEBUG_WEBGL ? 'u_projectionMatrix' : 'h');
26393
26394 /**
26395 * @type {WebGLUniformLocation}
26396 */
26397 this.u_size = gl.getUniformLocation(
26398 program, ol.DEBUG_WEBGL ? 'u_size' : 'o');
26399
26400 /**
26401 * @type {number}
26402 */
26403 this.a_direction = gl.getAttribLocation(
26404 program, ol.DEBUG_WEBGL ? 'a_direction' : 'g');
26405
26406 /**
26407 * @type {number}
26408 */
26409 this.a_lastPos = gl.getAttribLocation(
26410 program, ol.DEBUG_WEBGL ? 'a_lastPos' : 'd');
26411
26412 /**
26413 * @type {number}
26414 */
26415 this.a_nextPos = gl.getAttribLocation(
26416 program, ol.DEBUG_WEBGL ? 'a_nextPos' : 'f');
26417
26418 /**
26419 * @type {number}
26420 */
26421 this.a_position = gl.getAttribLocation(
26422 program, ol.DEBUG_WEBGL ? 'a_position' : 'e');
26423 };
26424
26425}
26426
26427goog.provide('ol.render.webgl.LineStringReplay');
26428
26429goog.require('ol');
26430goog.require('ol.array');
26431goog.require('ol.color');
26432goog.require('ol.extent');
26433goog.require('ol.geom.flat.orient');
26434goog.require('ol.geom.flat.transform');
26435goog.require('ol.geom.flat.topology');
26436goog.require('ol.obj');
26437goog.require('ol.render.webgl');
26438goog.require('ol.render.webgl.Replay');
26439goog.require('ol.render.webgl.linestringreplay.defaultshader');
26440goog.require('ol.webgl');
26441goog.require('ol.webgl.Buffer');
26442
26443
26444if (ol.ENABLE_WEBGL) {
26445
26446 /**
26447 * @constructor
26448 * @extends {ol.render.webgl.Replay}
26449 * @param {number} tolerance Tolerance.
26450 * @param {ol.Extent} maxExtent Max extent.
26451 * @struct
26452 */
26453 ol.render.webgl.LineStringReplay = function(tolerance, maxExtent) {
26454 ol.render.webgl.Replay.call(this, tolerance, maxExtent);
26455
26456 /**
26457 * @private
26458 * @type {ol.render.webgl.linestringreplay.defaultshader.Locations}
26459 */
26460 this.defaultLocations_ = null;
26461
26462 /**
26463 * @private
26464 * @type {Array.<Array.<?>>}
26465 */
26466 this.styles_ = [];
26467
26468 /**
26469 * @private
26470 * @type {Array.<number>}
26471 */
26472 this.styleIndices_ = [];
26473
26474 /**
26475 * @private
26476 * @type {{strokeColor: (Array.<number>|null),
26477 * lineCap: (string|undefined),
26478 * lineDash: Array.<number>,
26479 * lineDashOffset: (number|undefined),
26480 * lineJoin: (string|undefined),
26481 * lineWidth: (number|undefined),
26482 * miterLimit: (number|undefined),
26483 * changed: boolean}|null}
26484 */
26485 this.state_ = {
26486 strokeColor: null,
26487 lineCap: undefined,
26488 lineDash: null,
26489 lineDashOffset: undefined,
26490 lineJoin: undefined,
26491 lineWidth: undefined,
26492 miterLimit: undefined,
26493 changed: false
26494 };
26495
26496 };
26497 ol.inherits(ol.render.webgl.LineStringReplay, ol.render.webgl.Replay);
26498
26499
26500 /**
26501 * Draw one segment.
26502 * @private
26503 * @param {Array.<number>} flatCoordinates Flat coordinates.
26504 * @param {number} offset Offset.
26505 * @param {number} end End.
26506 * @param {number} stride Stride.
26507 */
26508 ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {
26509
26510 var i, ii;
26511 var numVertices = this.vertices.length;
26512 var numIndices = this.indices.length;
26513 //To save a vertex, the direction of a point is a product of the sign (1 or -1), a prime from
26514 //ol.render.webgl.LineStringReplay.Instruction_, and a rounding factor (1 or 2). If the product is even,
26515 //we round it. If it is odd, we don't.
26516 var lineJoin = this.state_.lineJoin === 'bevel' ? 0 :
26517 this.state_.lineJoin === 'miter' ? 1 : 2;
26518 var lineCap = this.state_.lineCap === 'butt' ? 0 :
26519 this.state_.lineCap === 'square' ? 1 : 2;
26520 var closed = ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, offset, end, stride);
26521 var startCoords, sign, n;
26522 var lastIndex = numIndices;
26523 var lastSign = 1;
26524 //We need the adjacent vertices to define normals in joins. p0 = last, p1 = current, p2 = next.
26525 var p0, p1, p2;
26526
26527 for (i = offset, ii = end; i < ii; i += stride) {
26528
26529 n = numVertices / 7;
26530
26531 p0 = p1;
26532 p1 = p2 || [flatCoordinates[i], flatCoordinates[i + 1]];
26533 //First vertex.
26534 if (i === offset) {
26535 p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]];
26536 if (end - offset === stride * 2 && ol.array.equals(p1, p2)) {
26537 break;
26538 }
26539 if (closed) {
26540 //A closed line! Complete the circle.
26541 p0 = [flatCoordinates[end - stride * 2],
26542 flatCoordinates[end - stride * 2 + 1]];
26543
26544 startCoords = p2;
26545 } else {
26546 //Add the first two/four vertices.
26547
26548 if (lineCap) {
26549 numVertices = this.addVertices_([0, 0], p1, p2,
26550 lastSign * ol.render.webgl.LineStringReplay.Instruction_.BEGIN_LINE_CAP * lineCap, numVertices);
26551
26552 numVertices = this.addVertices_([0, 0], p1, p2,
26553 -lastSign * ol.render.webgl.LineStringReplay.Instruction_.BEGIN_LINE_CAP * lineCap, numVertices);
26554
26555 this.indices[numIndices++] = n + 2;
26556 this.indices[numIndices++] = n;
26557 this.indices[numIndices++] = n + 1;
26558
26559 this.indices[numIndices++] = n + 1;
26560 this.indices[numIndices++] = n + 3;
26561 this.indices[numIndices++] = n + 2;
26562
26563 }
26564
26565 numVertices = this.addVertices_([0, 0], p1, p2,
26566 lastSign * ol.render.webgl.LineStringReplay.Instruction_.BEGIN_LINE * (lineCap || 1), numVertices);
26567
26568 numVertices = this.addVertices_([0, 0], p1, p2,
26569 -lastSign * ol.render.webgl.LineStringReplay.Instruction_.BEGIN_LINE * (lineCap || 1), numVertices);
26570
26571 lastIndex = numVertices / 7 - 1;
26572
26573 continue;
26574 }
26575 } else if (i === end - stride) {
26576 //Last vertex.
26577 if (closed) {
26578 //Same as the first vertex.
26579 p2 = startCoords;
26580 break;
26581 } else {
26582 p0 = p0 || [0, 0];
26583
26584 numVertices = this.addVertices_(p0, p1, [0, 0],
26585 lastSign * ol.render.webgl.LineStringReplay.Instruction_.END_LINE * (lineCap || 1), numVertices);
26586
26587 numVertices = this.addVertices_(p0, p1, [0, 0],
26588 -lastSign * ol.render.webgl.LineStringReplay.Instruction_.END_LINE * (lineCap || 1), numVertices);
26589
26590 this.indices[numIndices++] = n;
26591 this.indices[numIndices++] = lastIndex - 1;
26592 this.indices[numIndices++] = lastIndex;
26593
26594 this.indices[numIndices++] = lastIndex;
26595 this.indices[numIndices++] = n + 1;
26596 this.indices[numIndices++] = n;
26597
26598 if (lineCap) {
26599 numVertices = this.addVertices_(p0, p1, [0, 0],
26600 lastSign * ol.render.webgl.LineStringReplay.Instruction_.END_LINE_CAP * lineCap, numVertices);
26601
26602 numVertices = this.addVertices_(p0, p1, [0, 0],
26603 -lastSign * ol.render.webgl.LineStringReplay.Instruction_.END_LINE_CAP * lineCap, numVertices);
26604
26605 this.indices[numIndices++] = n + 2;
26606 this.indices[numIndices++] = n;
26607 this.indices[numIndices++] = n + 1;
26608
26609 this.indices[numIndices++] = n + 1;
26610 this.indices[numIndices++] = n + 3;
26611 this.indices[numIndices++] = n + 2;
26612
26613 }
26614
26615 break;
26616 }
26617 } else {
26618 p2 = [flatCoordinates[i + stride], flatCoordinates[i + stride + 1]];
26619 }
26620
26621 // We group CW and straight lines, thus the not so inituitive CCW checking function.
26622 sign = ol.render.webgl.triangleIsCounterClockwise(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1])
26623 ? -1 : 1;
26624
26625 numVertices = this.addVertices_(p0, p1, p2,
26626 sign * ol.render.webgl.LineStringReplay.Instruction_.BEVEL_FIRST * (lineJoin || 1), numVertices);
26627
26628 numVertices = this.addVertices_(p0, p1, p2,
26629 sign * ol.render.webgl.LineStringReplay.Instruction_.BEVEL_SECOND * (lineJoin || 1), numVertices);
26630
26631 numVertices = this.addVertices_(p0, p1, p2,
26632 -sign * ol.render.webgl.LineStringReplay.Instruction_.MITER_BOTTOM * (lineJoin || 1), numVertices);
26633
26634 if (i > offset) {
26635 this.indices[numIndices++] = n;
26636 this.indices[numIndices++] = lastIndex - 1;
26637 this.indices[numIndices++] = lastIndex;
26638
26639 this.indices[numIndices++] = n + 2;
26640 this.indices[numIndices++] = n;
26641 this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1;
26642 }
26643
26644 this.indices[numIndices++] = n;
26645 this.indices[numIndices++] = n + 2;
26646 this.indices[numIndices++] = n + 1;
26647
26648 lastIndex = n + 2;
26649 lastSign = sign;
26650
26651 //Add miter
26652 if (lineJoin) {
26653 numVertices = this.addVertices_(p0, p1, p2,
26654 sign * ol.render.webgl.LineStringReplay.Instruction_.MITER_TOP * lineJoin, numVertices);
26655
26656 this.indices[numIndices++] = n + 1;
26657 this.indices[numIndices++] = n + 3;
26658 this.indices[numIndices++] = n;
26659 }
26660 }
26661
26662 if (closed) {
26663 n = n || numVertices / 7;
26664 sign = ol.geom.flat.orient.linearRingIsClockwise([p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]], 0, 6, 2)
26665 ? 1 : -1;
26666
26667 numVertices = this.addVertices_(p0, p1, p2,
26668 sign * ol.render.webgl.LineStringReplay.Instruction_.BEVEL_FIRST * (lineJoin || 1), numVertices);
26669
26670 numVertices = this.addVertices_(p0, p1, p2,
26671 -sign * ol.render.webgl.LineStringReplay.Instruction_.MITER_BOTTOM * (lineJoin || 1), numVertices);
26672
26673 this.indices[numIndices++] = n;
26674 this.indices[numIndices++] = lastIndex - 1;
26675 this.indices[numIndices++] = lastIndex;
26676
26677 this.indices[numIndices++] = n + 1;
26678 this.indices[numIndices++] = n;
26679 this.indices[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1;
26680 }
26681 };
26682
26683 /**
26684 * @param {Array.<number>} p0 Last coordinates.
26685 * @param {Array.<number>} p1 Current coordinates.
26686 * @param {Array.<number>} p2 Next coordinates.
26687 * @param {number} product Sign, instruction, and rounding product.
26688 * @param {number} numVertices Vertex counter.
26689 * @return {number} Vertex counter.
26690 * @private
26691 */
26692 ol.render.webgl.LineStringReplay.prototype.addVertices_ = function(p0, p1, p2, product, numVertices) {
26693 this.vertices[numVertices++] = p0[0];
26694 this.vertices[numVertices++] = p0[1];
26695 this.vertices[numVertices++] = p1[0];
26696 this.vertices[numVertices++] = p1[1];
26697 this.vertices[numVertices++] = p2[0];
26698 this.vertices[numVertices++] = p2[1];
26699 this.vertices[numVertices++] = product;
26700
26701 return numVertices;
26702 };
26703
26704 /**
26705 * Check if the linestring can be drawn (i. e. valid).
26706 * @param {Array.<number>} flatCoordinates Flat coordinates.
26707 * @param {number} offset Offset.
26708 * @param {number} end End.
26709 * @param {number} stride Stride.
26710 * @return {boolean} The linestring can be drawn.
26711 * @private
26712 */
26713 ol.render.webgl.LineStringReplay.prototype.isValid_ = function(flatCoordinates, offset, end, stride) {
26714 var range = end - offset;
26715 if (range < stride * 2) {
26716 return false;
26717 } else if (range === stride * 2) {
26718 var firstP = [flatCoordinates[offset], flatCoordinates[offset + 1]];
26719 var lastP = [flatCoordinates[offset + stride], flatCoordinates[offset + stride + 1]];
26720 return !ol.array.equals(firstP, lastP);
26721 }
26722
26723 return true;
26724 };
26725
26726
26727 /**
26728 * @inheritDoc
26729 */
26730 ol.render.webgl.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {
26731 var flatCoordinates = lineStringGeometry.getFlatCoordinates();
26732 var stride = lineStringGeometry.getStride();
26733 if (this.isValid_(flatCoordinates, 0, flatCoordinates.length, stride)) {
26734 flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, flatCoordinates.length,
26735 stride, -this.origin[0], -this.origin[1]);
26736 if (this.state_.changed) {
26737 this.styleIndices_.push(this.indices.length);
26738 this.state_.changed = false;
26739 }
26740 this.startIndices.push(this.indices.length);
26741 this.startIndicesFeature.push(feature);
26742 this.drawCoordinates_(
26743 flatCoordinates, 0, flatCoordinates.length, stride);
26744 }
26745 };
26746
26747
26748 /**
26749 * @inheritDoc
26750 */
26751 ol.render.webgl.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {
26752 var indexCount = this.indices.length;
26753 var ends = multiLineStringGeometry.getEnds();
26754 ends.unshift(0);
26755 var flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
26756 var stride = multiLineStringGeometry.getStride();
26757 var i, ii;
26758 if (ends.length > 1) {
26759 for (i = 1, ii = ends.length; i < ii; ++i) {
26760 if (this.isValid_(flatCoordinates, ends[i - 1], ends[i], stride)) {
26761 var lineString = ol.geom.flat.transform.translate(flatCoordinates, ends[i - 1], ends[i],
26762 stride, -this.origin[0], -this.origin[1]);
26763 this.drawCoordinates_(
26764 lineString, 0, lineString.length, stride);
26765 }
26766 }
26767 }
26768 if (this.indices.length > indexCount) {
26769 this.startIndices.push(indexCount);
26770 this.startIndicesFeature.push(feature);
26771 if (this.state_.changed) {
26772 this.styleIndices_.push(indexCount);
26773 this.state_.changed = false;
26774 }
26775 }
26776 };
26777
26778
26779 /**
26780 * @param {Array.<number>} flatCoordinates Flat coordinates.
26781 * @param {Array.<Array.<number>>} holeFlatCoordinates Hole flat coordinates.
26782 * @param {number} stride Stride.
26783 */
26784 ol.render.webgl.LineStringReplay.prototype.drawPolygonCoordinates = function(
26785 flatCoordinates, holeFlatCoordinates, stride) {
26786 if (!ol.geom.flat.topology.lineStringIsClosed(flatCoordinates, 0,
26787 flatCoordinates.length, stride)) {
26788 flatCoordinates.push(flatCoordinates[0]);
26789 flatCoordinates.push(flatCoordinates[1]);
26790 }
26791 this.drawCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);
26792 if (holeFlatCoordinates.length) {
26793 var i, ii;
26794 for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) {
26795 if (!ol.geom.flat.topology.lineStringIsClosed(holeFlatCoordinates[i], 0,
26796 holeFlatCoordinates[i].length, stride)) {
26797 holeFlatCoordinates[i].push(holeFlatCoordinates[i][0]);
26798 holeFlatCoordinates[i].push(holeFlatCoordinates[i][1]);
26799 }
26800 this.drawCoordinates_(holeFlatCoordinates[i], 0,
26801 holeFlatCoordinates[i].length, stride);
26802 }
26803 }
26804 };
26805
26806
26807 /**
26808 * @param {ol.Feature|ol.render.Feature} feature Feature.
26809 * @param {number=} opt_index Index count.
26810 */
26811 ol.render.webgl.LineStringReplay.prototype.setPolygonStyle = function(feature, opt_index) {
26812 var index = opt_index === undefined ? this.indices.length : opt_index;
26813 this.startIndices.push(index);
26814 this.startIndicesFeature.push(feature);
26815 if (this.state_.changed) {
26816 this.styleIndices_.push(index);
26817 this.state_.changed = false;
26818 }
26819 };
26820
26821
26822 /**
26823 * @return {number} Current index.
26824 */
26825 ol.render.webgl.LineStringReplay.prototype.getCurrentIndex = function() {
26826 return this.indices.length;
26827 };
26828
26829
26830 /**
26831 * @inheritDoc
26832 **/
26833 ol.render.webgl.LineStringReplay.prototype.finish = function(context) {
26834 // create, bind, and populate the vertices buffer
26835 this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
26836
26837 // create, bind, and populate the indices buffer
26838 this.indicesBuffer = new ol.webgl.Buffer(this.indices);
26839
26840 this.startIndices.push(this.indices.length);
26841
26842 //Clean up, if there is nothing to draw
26843 if (this.styleIndices_.length === 0 && this.styles_.length > 0) {
26844 this.styles_ = [];
26845 }
26846
26847 this.vertices = null;
26848 this.indices = null;
26849 };
26850
26851
26852 /**
26853 * @inheritDoc
26854 */
26855 ol.render.webgl.LineStringReplay.prototype.getDeleteResourcesFunction = function(context) {
26856 var verticesBuffer = this.verticesBuffer;
26857 var indicesBuffer = this.indicesBuffer;
26858 return function() {
26859 context.deleteBuffer(verticesBuffer);
26860 context.deleteBuffer(indicesBuffer);
26861 };
26862 };
26863
26864
26865 /**
26866 * @inheritDoc
26867 */
26868 ol.render.webgl.LineStringReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {
26869 // get the program
26870 var fragmentShader, vertexShader;
26871 fragmentShader = ol.render.webgl.linestringreplay.defaultshader.fragment;
26872 vertexShader = ol.render.webgl.linestringreplay.defaultshader.vertex;
26873 var program = context.getProgram(fragmentShader, vertexShader);
26874
26875 // get the locations
26876 var locations;
26877 if (!this.defaultLocations_) {
26878 // eslint-disable-next-line openlayers-internal/no-missing-requires
26879 locations = new ol.render.webgl.linestringreplay.defaultshader.Locations(gl, program);
26880 this.defaultLocations_ = locations;
26881 } else {
26882 locations = this.defaultLocations_;
26883 }
26884
26885 context.useProgram(program);
26886
26887 // enable the vertex attrib arrays
26888 gl.enableVertexAttribArray(locations.a_lastPos);
26889 gl.vertexAttribPointer(locations.a_lastPos, 2, ol.webgl.FLOAT,
26890 false, 28, 0);
26891
26892 gl.enableVertexAttribArray(locations.a_position);
26893 gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,
26894 false, 28, 8);
26895
26896 gl.enableVertexAttribArray(locations.a_nextPos);
26897 gl.vertexAttribPointer(locations.a_nextPos, 2, ol.webgl.FLOAT,
26898 false, 28, 16);
26899
26900 gl.enableVertexAttribArray(locations.a_direction);
26901 gl.vertexAttribPointer(locations.a_direction, 1, ol.webgl.FLOAT,
26902 false, 28, 24);
26903
26904 // Enable renderer specific uniforms.
26905 gl.uniform2fv(locations.u_size, size);
26906 gl.uniform1f(locations.u_pixelRatio, pixelRatio);
26907
26908 return locations;
26909 };
26910
26911
26912 /**
26913 * @inheritDoc
26914 */
26915 ol.render.webgl.LineStringReplay.prototype.shutDownProgram = function(gl, locations) {
26916 gl.disableVertexAttribArray(locations.a_lastPos);
26917 gl.disableVertexAttribArray(locations.a_position);
26918 gl.disableVertexAttribArray(locations.a_nextPos);
26919 gl.disableVertexAttribArray(locations.a_direction);
26920 };
26921
26922
26923 /**
26924 * @inheritDoc
26925 */
26926 ol.render.webgl.LineStringReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {
26927 //Save GL parameters.
26928 var tmpDepthFunc = /** @type {number} */ (gl.getParameter(gl.DEPTH_FUNC));
26929 var tmpDepthMask = /** @type {boolean} */ (gl.getParameter(gl.DEPTH_WRITEMASK));
26930
26931 if (!hitDetection) {
26932 gl.enable(gl.DEPTH_TEST);
26933 gl.depthMask(true);
26934 gl.depthFunc(gl.NOTEQUAL);
26935 }
26936
26937 if (!ol.obj.isEmpty(skippedFeaturesHash)) {
26938 this.drawReplaySkipping_(gl, context, skippedFeaturesHash);
26939 } else {
26940 //Draw by style groups to minimize drawElements() calls.
26941 var i, start, end, nextStyle;
26942 end = this.startIndices[this.startIndices.length - 1];
26943 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
26944 start = this.styleIndices_[i];
26945 nextStyle = this.styles_[i];
26946 this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);
26947 this.drawElements(gl, context, start, end);
26948 gl.clear(gl.DEPTH_BUFFER_BIT);
26949 end = start;
26950 }
26951 }
26952 if (!hitDetection) {
26953 gl.disable(gl.DEPTH_TEST);
26954 gl.clear(gl.DEPTH_BUFFER_BIT);
26955 //Restore GL parameters.
26956 gl.depthMask(tmpDepthMask);
26957 gl.depthFunc(tmpDepthFunc);
26958 }
26959 };
26960
26961
26962 /**
26963 * @private
26964 * @param {WebGLRenderingContext} gl gl.
26965 * @param {ol.webgl.Context} context Context.
26966 * @param {Object} skippedFeaturesHash Ids of features to skip.
26967 */
26968 ol.render.webgl.LineStringReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {
26969 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;
26970 featureIndex = this.startIndices.length - 2;
26971 end = start = this.startIndices[featureIndex + 1];
26972 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
26973 nextStyle = this.styles_[i];
26974 this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);
26975 groupStart = this.styleIndices_[i];
26976
26977 while (featureIndex >= 0 &&
26978 this.startIndices[featureIndex] >= groupStart) {
26979 featureStart = this.startIndices[featureIndex];
26980 feature = this.startIndicesFeature[featureIndex];
26981 featureUid = ol.getUid(feature).toString();
26982
26983 if (skippedFeaturesHash[featureUid]) {
26984 if (start !== end) {
26985 this.drawElements(gl, context, start, end);
26986 gl.clear(gl.DEPTH_BUFFER_BIT);
26987 }
26988 end = featureStart;
26989 }
26990 featureIndex--;
26991 start = featureStart;
26992 }
26993 if (start !== end) {
26994 this.drawElements(gl, context, start, end);
26995 gl.clear(gl.DEPTH_BUFFER_BIT);
26996 }
26997 start = end = groupStart;
26998 }
26999 };
27000
27001
27002 /**
27003 * @inheritDoc
27004 */
27005 ol.render.webgl.LineStringReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,
27006 featureCallback, opt_hitExtent) {
27007 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;
27008 featureIndex = this.startIndices.length - 2;
27009 end = this.startIndices[featureIndex + 1];
27010 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
27011 nextStyle = this.styles_[i];
27012 this.setStrokeStyle_(gl, nextStyle[0], nextStyle[1], nextStyle[2]);
27013 groupStart = this.styleIndices_[i];
27014
27015 while (featureIndex >= 0 &&
27016 this.startIndices[featureIndex] >= groupStart) {
27017 start = this.startIndices[featureIndex];
27018 feature = this.startIndicesFeature[featureIndex];
27019 featureUid = ol.getUid(feature).toString();
27020
27021 if (skippedFeaturesHash[featureUid] === undefined &&
27022 feature.getGeometry() &&
27023 (opt_hitExtent === undefined || ol.extent.intersects(
27024 /** @type {Array<number>} */ (opt_hitExtent),
27025 feature.getGeometry().getExtent()))) {
27026 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
27027 this.drawElements(gl, context, start, end);
27028
27029 var result = featureCallback(feature);
27030
27031 if (result) {
27032 return result;
27033 }
27034
27035 }
27036 featureIndex--;
27037 end = start;
27038 }
27039 }
27040 return undefined;
27041 };
27042
27043
27044 /**
27045 * @private
27046 * @param {WebGLRenderingContext} gl gl.
27047 * @param {Array.<number>} color Color.
27048 * @param {number} lineWidth Line width.
27049 * @param {number} miterLimit Miter limit.
27050 */
27051 ol.render.webgl.LineStringReplay.prototype.setStrokeStyle_ = function(gl, color, lineWidth, miterLimit) {
27052 gl.uniform4fv(this.defaultLocations_.u_color, color);
27053 gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth);
27054 gl.uniform1f(this.defaultLocations_.u_miterLimit, miterLimit);
27055 };
27056
27057
27058 /**
27059 * @inheritDoc
27060 */
27061 ol.render.webgl.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
27062 var strokeStyleLineCap = strokeStyle.getLineCap();
27063 this.state_.lineCap = strokeStyleLineCap !== undefined ?
27064 strokeStyleLineCap : ol.render.webgl.defaultLineCap;
27065 var strokeStyleLineDash = strokeStyle.getLineDash();
27066 this.state_.lineDash = strokeStyleLineDash ?
27067 strokeStyleLineDash : ol.render.webgl.defaultLineDash;
27068 var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
27069 this.state_.lineDashOffset = strokeStyleLineDashOffset ?
27070 strokeStyleLineDashOffset : ol.render.webgl.defaultLineDashOffset;
27071 var strokeStyleLineJoin = strokeStyle.getLineJoin();
27072 this.state_.lineJoin = strokeStyleLineJoin !== undefined ?
27073 strokeStyleLineJoin : ol.render.webgl.defaultLineJoin;
27074 var strokeStyleColor = strokeStyle.getColor();
27075 if (!(strokeStyleColor instanceof CanvasGradient) &&
27076 !(strokeStyleColor instanceof CanvasPattern)) {
27077 strokeStyleColor = ol.color.asArray(strokeStyleColor).map(function(c, i) {
27078 return i != 3 ? c / 255 : c;
27079 }) || ol.render.webgl.defaultStrokeStyle;
27080 } else {
27081 strokeStyleColor = ol.render.webgl.defaultStrokeStyle;
27082 }
27083 var strokeStyleWidth = strokeStyle.getWidth();
27084 strokeStyleWidth = strokeStyleWidth !== undefined ?
27085 strokeStyleWidth : ol.render.webgl.defaultLineWidth;
27086 var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
27087 strokeStyleMiterLimit = strokeStyleMiterLimit !== undefined ?
27088 strokeStyleMiterLimit : ol.render.webgl.defaultMiterLimit;
27089 if (!this.state_.strokeColor || !ol.array.equals(this.state_.strokeColor, strokeStyleColor) ||
27090 this.state_.lineWidth !== strokeStyleWidth || this.state_.miterLimit !== strokeStyleMiterLimit) {
27091 this.state_.changed = true;
27092 this.state_.strokeColor = strokeStyleColor;
27093 this.state_.lineWidth = strokeStyleWidth;
27094 this.state_.miterLimit = strokeStyleMiterLimit;
27095 this.styles_.push([strokeStyleColor, strokeStyleWidth, strokeStyleMiterLimit]);
27096 }
27097 };
27098
27099 /**
27100 * @enum {number}
27101 * @private
27102 */
27103 ol.render.webgl.LineStringReplay.Instruction_ = {
27104 ROUND: 2,
27105 BEGIN_LINE: 3,
27106 END_LINE: 5,
27107 BEGIN_LINE_CAP: 7,
27108 END_LINE_CAP: 11,
27109 BEVEL_FIRST: 13,
27110 BEVEL_SECOND: 17,
27111 MITER_BOTTOM: 19,
27112 MITER_TOP: 23
27113 };
27114
27115}
27116
27117// This file is automatically generated, do not edit
27118/* eslint openlayers-internal/no-missing-requires: 0 */
27119goog.provide('ol.render.webgl.polygonreplay.defaultshader');
27120
27121goog.require('ol');
27122goog.require('ol.webgl.Fragment');
27123goog.require('ol.webgl.Vertex');
27124
27125if (ol.ENABLE_WEBGL) {
27126
27127 /**
27128 * @constructor
27129 * @extends {ol.webgl.Fragment}
27130 * @struct
27131 */
27132 ol.render.webgl.polygonreplay.defaultshader.Fragment = function() {
27133 ol.webgl.Fragment.call(this, ol.render.webgl.polygonreplay.defaultshader.Fragment.SOURCE);
27134 };
27135 ol.inherits(ol.render.webgl.polygonreplay.defaultshader.Fragment, ol.webgl.Fragment);
27136
27137
27138 /**
27139 * @const
27140 * @type {string}
27141 */
27142 ol.render.webgl.polygonreplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\n\n\n\nuniform vec4 u_color;\nuniform float u_opacity;\n\nvoid main(void) {\n gl_FragColor = u_color;\n float alpha = u_color.a * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n';
27143
27144
27145 /**
27146 * @const
27147 * @type {string}
27148 */
27149 ol.render.webgl.polygonreplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;uniform vec4 e;uniform float f;void main(void){gl_FragColor=e;float alpha=e.a*f;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}';
27150
27151
27152 /**
27153 * @const
27154 * @type {string}
27155 */
27156 ol.render.webgl.polygonreplay.defaultshader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
27157 ol.render.webgl.polygonreplay.defaultshader.Fragment.DEBUG_SOURCE :
27158 ol.render.webgl.polygonreplay.defaultshader.Fragment.OPTIMIZED_SOURCE;
27159
27160
27161 ol.render.webgl.polygonreplay.defaultshader.fragment = new ol.render.webgl.polygonreplay.defaultshader.Fragment();
27162
27163
27164 /**
27165 * @constructor
27166 * @extends {ol.webgl.Vertex}
27167 * @struct
27168 */
27169 ol.render.webgl.polygonreplay.defaultshader.Vertex = function() {
27170 ol.webgl.Vertex.call(this, ol.render.webgl.polygonreplay.defaultshader.Vertex.SOURCE);
27171 };
27172 ol.inherits(ol.render.webgl.polygonreplay.defaultshader.Vertex, ol.webgl.Vertex);
27173
27174
27175 /**
27176 * @const
27177 * @type {string}
27178 */
27179 ol.render.webgl.polygonreplay.defaultshader.Vertex.DEBUG_SOURCE = '\n\nattribute vec2 a_position;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\n\nvoid main(void) {\n gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0);\n}\n\n\n';
27180
27181
27182 /**
27183 * @const
27184 * @type {string}
27185 */
27186 ol.render.webgl.polygonreplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'attribute vec2 a;uniform mat4 b;uniform mat4 c;uniform mat4 d;void main(void){gl_Position=b*vec4(a,0.0,1.0);}';
27187
27188
27189 /**
27190 * @const
27191 * @type {string}
27192 */
27193 ol.render.webgl.polygonreplay.defaultshader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
27194 ol.render.webgl.polygonreplay.defaultshader.Vertex.DEBUG_SOURCE :
27195 ol.render.webgl.polygonreplay.defaultshader.Vertex.OPTIMIZED_SOURCE;
27196
27197
27198 ol.render.webgl.polygonreplay.defaultshader.vertex = new ol.render.webgl.polygonreplay.defaultshader.Vertex();
27199
27200
27201 /**
27202 * @constructor
27203 * @param {WebGLRenderingContext} gl GL.
27204 * @param {WebGLProgram} program Program.
27205 * @struct
27206 */
27207 ol.render.webgl.polygonreplay.defaultshader.Locations = function(gl, program) {
27208
27209 /**
27210 * @type {WebGLUniformLocation}
27211 */
27212 this.u_color = gl.getUniformLocation(
27213 program, ol.DEBUG_WEBGL ? 'u_color' : 'e');
27214
27215 /**
27216 * @type {WebGLUniformLocation}
27217 */
27218 this.u_offsetRotateMatrix = gl.getUniformLocation(
27219 program, ol.DEBUG_WEBGL ? 'u_offsetRotateMatrix' : 'd');
27220
27221 /**
27222 * @type {WebGLUniformLocation}
27223 */
27224 this.u_offsetScaleMatrix = gl.getUniformLocation(
27225 program, ol.DEBUG_WEBGL ? 'u_offsetScaleMatrix' : 'c');
27226
27227 /**
27228 * @type {WebGLUniformLocation}
27229 */
27230 this.u_opacity = gl.getUniformLocation(
27231 program, ol.DEBUG_WEBGL ? 'u_opacity' : 'f');
27232
27233 /**
27234 * @type {WebGLUniformLocation}
27235 */
27236 this.u_projectionMatrix = gl.getUniformLocation(
27237 program, ol.DEBUG_WEBGL ? 'u_projectionMatrix' : 'b');
27238
27239 /**
27240 * @type {number}
27241 */
27242 this.a_position = gl.getAttribLocation(
27243 program, ol.DEBUG_WEBGL ? 'a_position' : 'a');
27244 };
27245
27246}
27247
27248goog.provide('ol.style.Stroke');
27249
27250goog.require('ol');
27251
27252
27253/**
27254 * @classdesc
27255 * Set stroke style for vector features.
27256 * Note that the defaults given are the Canvas defaults, which will be used if
27257 * option is not defined. The `get` functions return whatever was entered in
27258 * the options; they will not return the default.
27259 *
27260 * @constructor
27261 * @param {olx.style.StrokeOptions=} opt_options Options.
27262 * @api
27263 */
27264ol.style.Stroke = function(opt_options) {
27265
27266 var options = opt_options || {};
27267
27268 /**
27269 * @private
27270 * @type {ol.Color|ol.ColorLike}
27271 */
27272 this.color_ = options.color !== undefined ? options.color : null;
27273
27274 /**
27275 * @private
27276 * @type {string|undefined}
27277 */
27278 this.lineCap_ = options.lineCap;
27279
27280 /**
27281 * @private
27282 * @type {Array.<number>}
27283 */
27284 this.lineDash_ = options.lineDash !== undefined ? options.lineDash : null;
27285
27286 /**
27287 * @private
27288 * @type {number|undefined}
27289 */
27290 this.lineDashOffset_ = options.lineDashOffset;
27291
27292 /**
27293 * @private
27294 * @type {string|undefined}
27295 */
27296 this.lineJoin_ = options.lineJoin;
27297
27298 /**
27299 * @private
27300 * @type {number|undefined}
27301 */
27302 this.miterLimit_ = options.miterLimit;
27303
27304 /**
27305 * @private
27306 * @type {number|undefined}
27307 */
27308 this.width_ = options.width;
27309
27310 /**
27311 * @private
27312 * @type {string|undefined}
27313 */
27314 this.checksum_ = undefined;
27315};
27316
27317
27318/**
27319 * Clones the style.
27320 * @return {ol.style.Stroke} The cloned style.
27321 * @api
27322 */
27323ol.style.Stroke.prototype.clone = function() {
27324 var color = this.getColor();
27325 return new ol.style.Stroke({
27326 color: (color && color.slice) ? color.slice() : color || undefined,
27327 lineCap: this.getLineCap(),
27328 lineDash: this.getLineDash() ? this.getLineDash().slice() : undefined,
27329 lineDashOffset: this.getLineDashOffset(),
27330 lineJoin: this.getLineJoin(),
27331 miterLimit: this.getMiterLimit(),
27332 width: this.getWidth()
27333 });
27334};
27335
27336
27337/**
27338 * Get the stroke color.
27339 * @return {ol.Color|ol.ColorLike} Color.
27340 * @api
27341 */
27342ol.style.Stroke.prototype.getColor = function() {
27343 return this.color_;
27344};
27345
27346
27347/**
27348 * Get the line cap type for the stroke.
27349 * @return {string|undefined} Line cap.
27350 * @api
27351 */
27352ol.style.Stroke.prototype.getLineCap = function() {
27353 return this.lineCap_;
27354};
27355
27356
27357/**
27358 * Get the line dash style for the stroke.
27359 * @return {Array.<number>} Line dash.
27360 * @api
27361 */
27362ol.style.Stroke.prototype.getLineDash = function() {
27363 return this.lineDash_;
27364};
27365
27366
27367/**
27368 * Get the line dash offset for the stroke.
27369 * @return {number|undefined} Line dash offset.
27370 * @api
27371 */
27372ol.style.Stroke.prototype.getLineDashOffset = function() {
27373 return this.lineDashOffset_;
27374};
27375
27376
27377/**
27378 * Get the line join type for the stroke.
27379 * @return {string|undefined} Line join.
27380 * @api
27381 */
27382ol.style.Stroke.prototype.getLineJoin = function() {
27383 return this.lineJoin_;
27384};
27385
27386
27387/**
27388 * Get the miter limit for the stroke.
27389 * @return {number|undefined} Miter limit.
27390 * @api
27391 */
27392ol.style.Stroke.prototype.getMiterLimit = function() {
27393 return this.miterLimit_;
27394};
27395
27396
27397/**
27398 * Get the stroke width.
27399 * @return {number|undefined} Width.
27400 * @api
27401 */
27402ol.style.Stroke.prototype.getWidth = function() {
27403 return this.width_;
27404};
27405
27406
27407/**
27408 * Set the color.
27409 *
27410 * @param {ol.Color|ol.ColorLike} color Color.
27411 * @api
27412 */
27413ol.style.Stroke.prototype.setColor = function(color) {
27414 this.color_ = color;
27415 this.checksum_ = undefined;
27416};
27417
27418
27419/**
27420 * Set the line cap.
27421 *
27422 * @param {string|undefined} lineCap Line cap.
27423 * @api
27424 */
27425ol.style.Stroke.prototype.setLineCap = function(lineCap) {
27426 this.lineCap_ = lineCap;
27427 this.checksum_ = undefined;
27428};
27429
27430
27431/**
27432 * Set the line dash.
27433 *
27434 * Please note that Internet Explorer 10 and lower [do not support][mdn] the
27435 * `setLineDash` method on the `CanvasRenderingContext2D` and therefore this
27436 * property will have no visual effect in these browsers.
27437 *
27438 * [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility
27439 *
27440 * @param {Array.<number>} lineDash Line dash.
27441 * @api
27442 */
27443ol.style.Stroke.prototype.setLineDash = function(lineDash) {
27444 this.lineDash_ = lineDash;
27445 this.checksum_ = undefined;
27446};
27447
27448
27449/**
27450 * Set the line dash offset.
27451 *
27452 * @param {number|undefined} lineDashOffset Line dash offset.
27453 * @api
27454 */
27455ol.style.Stroke.prototype.setLineDashOffset = function(lineDashOffset) {
27456 this.lineDashOffset_ = lineDashOffset;
27457 this.checksum_ = undefined;
27458};
27459
27460
27461/**
27462 * Set the line join.
27463 *
27464 * @param {string|undefined} lineJoin Line join.
27465 * @api
27466 */
27467ol.style.Stroke.prototype.setLineJoin = function(lineJoin) {
27468 this.lineJoin_ = lineJoin;
27469 this.checksum_ = undefined;
27470};
27471
27472
27473/**
27474 * Set the miter limit.
27475 *
27476 * @param {number|undefined} miterLimit Miter limit.
27477 * @api
27478 */
27479ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) {
27480 this.miterLimit_ = miterLimit;
27481 this.checksum_ = undefined;
27482};
27483
27484
27485/**
27486 * Set the width.
27487 *
27488 * @param {number|undefined} width Width.
27489 * @api
27490 */
27491ol.style.Stroke.prototype.setWidth = function(width) {
27492 this.width_ = width;
27493 this.checksum_ = undefined;
27494};
27495
27496
27497/**
27498 * @return {string} The checksum.
27499 */
27500ol.style.Stroke.prototype.getChecksum = function() {
27501 if (this.checksum_ === undefined) {
27502 this.checksum_ = 's';
27503 if (this.color_) {
27504 if (typeof this.color_ === 'string') {
27505 this.checksum_ += this.color_;
27506 } else {
27507 this.checksum_ += ol.getUid(this.color_).toString();
27508 }
27509 } else {
27510 this.checksum_ += '-';
27511 }
27512 this.checksum_ += ',' +
27513 (this.lineCap_ !== undefined ?
27514 this.lineCap_.toString() : '-') + ',' +
27515 (this.lineDash_ ?
27516 this.lineDash_.toString() : '-') + ',' +
27517 (this.lineDashOffset_ !== undefined ?
27518 this.lineDashOffset_ : '-') + ',' +
27519 (this.lineJoin_ !== undefined ?
27520 this.lineJoin_ : '-') + ',' +
27521 (this.miterLimit_ !== undefined ?
27522 this.miterLimit_.toString() : '-') + ',' +
27523 (this.width_ !== undefined ?
27524 this.width_.toString() : '-');
27525 }
27526
27527 return this.checksum_;
27528};
27529
27530goog.provide('ol.structs.LinkedList');
27531
27532/**
27533 * Creates an empty linked list structure.
27534 *
27535 * @constructor
27536 * @struct
27537 * @param {boolean=} opt_circular The last item is connected to the first one,
27538 * and the first item to the last one. Default is true.
27539 */
27540ol.structs.LinkedList = function(opt_circular) {
27541
27542 /**
27543 * @private
27544 * @type {ol.LinkedListItem|undefined}
27545 */
27546 this.first_ = undefined;
27547
27548 /**
27549 * @private
27550 * @type {ol.LinkedListItem|undefined}
27551 */
27552 this.last_ = undefined;
27553
27554 /**
27555 * @private
27556 * @type {ol.LinkedListItem|undefined}
27557 */
27558 this.head_ = undefined;
27559
27560 /**
27561 * @private
27562 * @type {boolean}
27563 */
27564 this.circular_ = opt_circular === undefined ? true : opt_circular;
27565
27566 /**
27567 * @private
27568 * @type {number}
27569 */
27570 this.length_ = 0;
27571};
27572
27573/**
27574 * Inserts an item into the linked list right after the current one.
27575 *
27576 * @param {?} data Item data.
27577 */
27578ol.structs.LinkedList.prototype.insertItem = function(data) {
27579
27580 /** @type {ol.LinkedListItem} */
27581 var item = {
27582 prev: undefined,
27583 next: undefined,
27584 data: data
27585 };
27586
27587 var head = this.head_;
27588
27589 //Initialize the list.
27590 if (!head) {
27591 this.first_ = item;
27592 this.last_ = item;
27593 if (this.circular_) {
27594 item.next = item;
27595 item.prev = item;
27596 }
27597 } else {
27598 //Link the new item to the adjacent ones.
27599 var next = head.next;
27600 item.prev = head;
27601 item.next = next;
27602 head.next = item;
27603 if (next) {
27604 next.prev = item;
27605 }
27606
27607 if (head === this.last_) {
27608 this.last_ = item;
27609 }
27610 }
27611 this.head_ = item;
27612 this.length_++;
27613};
27614
27615/**
27616 * Removes the current item from the list. Sets the cursor to the next item,
27617 * if possible.
27618 */
27619ol.structs.LinkedList.prototype.removeItem = function() {
27620 var head = this.head_;
27621 if (head) {
27622 var next = head.next;
27623 var prev = head.prev;
27624 if (next) {
27625 next.prev = prev;
27626 }
27627 if (prev) {
27628 prev.next = next;
27629 }
27630 this.head_ = next || prev;
27631
27632 if (this.first_ === this.last_) {
27633 this.head_ = undefined;
27634 this.first_ = undefined;
27635 this.last_ = undefined;
27636 } else if (this.first_ === head) {
27637 this.first_ = this.head_;
27638 } else if (this.last_ === head) {
27639 this.last_ = prev ? this.head_.prev : this.head_;
27640 }
27641 this.length_--;
27642 }
27643};
27644
27645/**
27646 * Sets the cursor to the first item, and returns the associated data.
27647 *
27648 * @return {?} Item data.
27649 */
27650ol.structs.LinkedList.prototype.firstItem = function() {
27651 this.head_ = this.first_;
27652 if (this.head_) {
27653 return this.head_.data;
27654 }
27655 return undefined;
27656};
27657
27658/**
27659* Sets the cursor to the last item, and returns the associated data.
27660*
27661* @return {?} Item data.
27662*/
27663ol.structs.LinkedList.prototype.lastItem = function() {
27664 this.head_ = this.last_;
27665 if (this.head_) {
27666 return this.head_.data;
27667 }
27668 return undefined;
27669};
27670
27671/**
27672 * Sets the cursor to the next item, and returns the associated data.
27673 *
27674 * @return {?} Item data.
27675 */
27676ol.structs.LinkedList.prototype.nextItem = function() {
27677 if (this.head_ && this.head_.next) {
27678 this.head_ = this.head_.next;
27679 return this.head_.data;
27680 }
27681 return undefined;
27682};
27683
27684/**
27685 * Returns the next item's data without moving the cursor.
27686 *
27687 * @return {?} Item data.
27688 */
27689ol.structs.LinkedList.prototype.getNextItem = function() {
27690 if (this.head_ && this.head_.next) {
27691 return this.head_.next.data;
27692 }
27693 return undefined;
27694};
27695
27696/**
27697 * Sets the cursor to the previous item, and returns the associated data.
27698 *
27699 * @return {?} Item data.
27700 */
27701ol.structs.LinkedList.prototype.prevItem = function() {
27702 if (this.head_ && this.head_.prev) {
27703 this.head_ = this.head_.prev;
27704 return this.head_.data;
27705 }
27706 return undefined;
27707};
27708
27709/**
27710 * Returns the previous item's data without moving the cursor.
27711 *
27712 * @return {?} Item data.
27713 */
27714ol.structs.LinkedList.prototype.getPrevItem = function() {
27715 if (this.head_ && this.head_.prev) {
27716 return this.head_.prev.data;
27717 }
27718 return undefined;
27719};
27720
27721/**
27722 * Returns the current item's data.
27723 *
27724 * @return {?} Item data.
27725 */
27726ol.structs.LinkedList.prototype.getCurrItem = function() {
27727 if (this.head_) {
27728 return this.head_.data;
27729 }
27730 return undefined;
27731};
27732
27733/**
27734 * Sets the first item of the list. This only works for circular lists, and sets
27735 * the last item accordingly.
27736 */
27737ol.structs.LinkedList.prototype.setFirstItem = function() {
27738 if (this.circular_ && this.head_) {
27739 this.first_ = this.head_;
27740 this.last_ = this.head_.prev;
27741 }
27742};
27743
27744/**
27745 * Concatenates two lists.
27746 * @param {ol.structs.LinkedList} list List to merge into the current list.
27747 */
27748ol.structs.LinkedList.prototype.concat = function(list) {
27749 if (list.head_) {
27750 if (this.head_) {
27751 var end = this.head_.next;
27752 this.head_.next = list.first_;
27753 list.first_.prev = this.head_;
27754 end.prev = list.last_;
27755 list.last_.next = end;
27756 this.length_ += list.length_;
27757 } else {
27758 this.head_ = list.head_;
27759 this.first_ = list.first_;
27760 this.last_ = list.last_;
27761 this.length_ = list.length_;
27762 }
27763 list.head_ = undefined;
27764 list.first_ = undefined;
27765 list.last_ = undefined;
27766 list.length_ = 0;
27767 }
27768};
27769
27770/**
27771 * Returns the current length of the list.
27772 *
27773 * @return {number} Length.
27774 */
27775ol.structs.LinkedList.prototype.getLength = function() {
27776 return this.length_;
27777};
27778
27779
27780/**
27781 * @fileoverview
27782 * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, unusedLocalVariables, uselessCode, visibility}
27783 */
27784goog.provide('ol.ext.rbush');
27785
27786/** @typedef {function(*)} */
27787ol.ext.rbush = function() {};
27788
27789(function() {(function (exports) {
27790'use strict';
27791
27792var index$2 = partialSort;
27793function partialSort(arr, k, left, right, compare) {
27794 left = left || 0;
27795 right = right || (arr.length - 1);
27796 compare = compare || defaultCompare;
27797 while (right > left) {
27798 if (right - left > 600) {
27799 var n = right - left + 1;
27800 var m = k - left + 1;
27801 var z = Math.log(n);
27802 var s = 0.5 * Math.exp(2 * z / 3);
27803 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
27804 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
27805 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
27806 partialSort(arr, k, newLeft, newRight, compare);
27807 }
27808 var t = arr[k];
27809 var i = left;
27810 var j = right;
27811 swap(arr, left, k);
27812 if (compare(arr[right], t) > 0) swap(arr, left, right);
27813 while (i < j) {
27814 swap(arr, i, j);
27815 i++;
27816 j--;
27817 while (compare(arr[i], t) < 0) i++;
27818 while (compare(arr[j], t) > 0) j--;
27819 }
27820 if (compare(arr[left], t) === 0) swap(arr, left, j);
27821 else {
27822 j++;
27823 swap(arr, j, right);
27824 }
27825 if (j <= k) left = j + 1;
27826 if (k <= j) right = j - 1;
27827 }
27828}
27829function swap(arr, i, j) {
27830 var tmp = arr[i];
27831 arr[i] = arr[j];
27832 arr[j] = tmp;
27833}
27834function defaultCompare(a, b) {
27835 return a < b ? -1 : a > b ? 1 : 0;
27836}
27837
27838var index = rbush;
27839function rbush(maxEntries, format) {
27840 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
27841 this._maxEntries = Math.max(4, maxEntries || 9);
27842 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
27843 if (format) {
27844 this._initFormat(format);
27845 }
27846 this.clear();
27847}
27848rbush.prototype = {
27849 all: function () {
27850 return this._all(this.data, []);
27851 },
27852 search: function (bbox) {
27853 var node = this.data,
27854 result = [],
27855 toBBox = this.toBBox;
27856 if (!intersects(bbox, node)) return result;
27857 var nodesToSearch = [],
27858 i, len, child, childBBox;
27859 while (node) {
27860 for (i = 0, len = node.children.length; i < len; i++) {
27861 child = node.children[i];
27862 childBBox = node.leaf ? toBBox(child) : child;
27863 if (intersects(bbox, childBBox)) {
27864 if (node.leaf) result.push(child);
27865 else if (contains(bbox, childBBox)) this._all(child, result);
27866 else nodesToSearch.push(child);
27867 }
27868 }
27869 node = nodesToSearch.pop();
27870 }
27871 return result;
27872 },
27873 collides: function (bbox) {
27874 var node = this.data,
27875 toBBox = this.toBBox;
27876 if (!intersects(bbox, node)) return false;
27877 var nodesToSearch = [],
27878 i, len, child, childBBox;
27879 while (node) {
27880 for (i = 0, len = node.children.length; i < len; i++) {
27881 child = node.children[i];
27882 childBBox = node.leaf ? toBBox(child) : child;
27883 if (intersects(bbox, childBBox)) {
27884 if (node.leaf || contains(bbox, childBBox)) return true;
27885 nodesToSearch.push(child);
27886 }
27887 }
27888 node = nodesToSearch.pop();
27889 }
27890 return false;
27891 },
27892 load: function (data) {
27893 if (!(data && data.length)) return this;
27894 if (data.length < this._minEntries) {
27895 for (var i = 0, len = data.length; i < len; i++) {
27896 this.insert(data[i]);
27897 }
27898 return this;
27899 }
27900 var node = this._build(data.slice(), 0, data.length - 1, 0);
27901 if (!this.data.children.length) {
27902 this.data = node;
27903 } else if (this.data.height === node.height) {
27904 this._splitRoot(this.data, node);
27905 } else {
27906 if (this.data.height < node.height) {
27907 var tmpNode = this.data;
27908 this.data = node;
27909 node = tmpNode;
27910 }
27911 this._insert(node, this.data.height - node.height - 1, true);
27912 }
27913 return this;
27914 },
27915 insert: function (item) {
27916 if (item) this._insert(item, this.data.height - 1);
27917 return this;
27918 },
27919 clear: function () {
27920 this.data = createNode([]);
27921 return this;
27922 },
27923 remove: function (item, equalsFn) {
27924 if (!item) return this;
27925 var node = this.data,
27926 bbox = this.toBBox(item),
27927 path = [],
27928 indexes = [],
27929 i, parent, index, goingUp;
27930 while (node || path.length) {
27931 if (!node) {
27932 node = path.pop();
27933 parent = path[path.length - 1];
27934 i = indexes.pop();
27935 goingUp = true;
27936 }
27937 if (node.leaf) {
27938 index = findItem(item, node.children, equalsFn);
27939 if (index !== -1) {
27940 node.children.splice(index, 1);
27941 path.push(node);
27942 this._condense(path);
27943 return this;
27944 }
27945 }
27946 if (!goingUp && !node.leaf && contains(node, bbox)) {
27947 path.push(node);
27948 indexes.push(i);
27949 i = 0;
27950 parent = node;
27951 node = node.children[0];
27952 } else if (parent) {
27953 i++;
27954 node = parent.children[i];
27955 goingUp = false;
27956 } else node = null;
27957 }
27958 return this;
27959 },
27960 toBBox: function (item) { return item; },
27961 compareMinX: compareNodeMinX,
27962 compareMinY: compareNodeMinY,
27963 toJSON: function () { return this.data; },
27964 fromJSON: function (data) {
27965 this.data = data;
27966 return this;
27967 },
27968 _all: function (node, result) {
27969 var nodesToSearch = [];
27970 while (node) {
27971 if (node.leaf) result.push.apply(result, node.children);
27972 else nodesToSearch.push.apply(nodesToSearch, node.children);
27973 node = nodesToSearch.pop();
27974 }
27975 return result;
27976 },
27977 _build: function (items, left, right, height) {
27978 var N = right - left + 1,
27979 M = this._maxEntries,
27980 node;
27981 if (N <= M) {
27982 node = createNode(items.slice(left, right + 1));
27983 calcBBox(node, this.toBBox);
27984 return node;
27985 }
27986 if (!height) {
27987 height = Math.ceil(Math.log(N) / Math.log(M));
27988 M = Math.ceil(N / Math.pow(M, height - 1));
27989 }
27990 node = createNode([]);
27991 node.leaf = false;
27992 node.height = height;
27993 var N2 = Math.ceil(N / M),
27994 N1 = N2 * Math.ceil(Math.sqrt(M)),
27995 i, j, right2, right3;
27996 multiSelect(items, left, right, N1, this.compareMinX);
27997 for (i = left; i <= right; i += N1) {
27998 right2 = Math.min(i + N1 - 1, right);
27999 multiSelect(items, i, right2, N2, this.compareMinY);
28000 for (j = i; j <= right2; j += N2) {
28001 right3 = Math.min(j + N2 - 1, right2);
28002 node.children.push(this._build(items, j, right3, height - 1));
28003 }
28004 }
28005 calcBBox(node, this.toBBox);
28006 return node;
28007 },
28008 _chooseSubtree: function (bbox, node, level, path) {
28009 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
28010 while (true) {
28011 path.push(node);
28012 if (node.leaf || path.length - 1 === level) break;
28013 minArea = minEnlargement = Infinity;
28014 for (i = 0, len = node.children.length; i < len; i++) {
28015 child = node.children[i];
28016 area = bboxArea(child);
28017 enlargement = enlargedArea(bbox, child) - area;
28018 if (enlargement < minEnlargement) {
28019 minEnlargement = enlargement;
28020 minArea = area < minArea ? area : minArea;
28021 targetNode = child;
28022 } else if (enlargement === minEnlargement) {
28023 if (area < minArea) {
28024 minArea = area;
28025 targetNode = child;
28026 }
28027 }
28028 }
28029 node = targetNode || node.children[0];
28030 }
28031 return node;
28032 },
28033 _insert: function (item, level, isNode) {
28034 var toBBox = this.toBBox,
28035 bbox = isNode ? item : toBBox(item),
28036 insertPath = [];
28037 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
28038 node.children.push(item);
28039 extend(node, bbox);
28040 while (level >= 0) {
28041 if (insertPath[level].children.length > this._maxEntries) {
28042 this._split(insertPath, level);
28043 level--;
28044 } else break;
28045 }
28046 this._adjustParentBBoxes(bbox, insertPath, level);
28047 },
28048 _split: function (insertPath, level) {
28049 var node = insertPath[level],
28050 M = node.children.length,
28051 m = this._minEntries;
28052 this._chooseSplitAxis(node, m, M);
28053 var splitIndex = this._chooseSplitIndex(node, m, M);
28054 var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
28055 newNode.height = node.height;
28056 newNode.leaf = node.leaf;
28057 calcBBox(node, this.toBBox);
28058 calcBBox(newNode, this.toBBox);
28059 if (level) insertPath[level - 1].children.push(newNode);
28060 else this._splitRoot(node, newNode);
28061 },
28062 _splitRoot: function (node, newNode) {
28063 this.data = createNode([node, newNode]);
28064 this.data.height = node.height + 1;
28065 this.data.leaf = false;
28066 calcBBox(this.data, this.toBBox);
28067 },
28068 _chooseSplitIndex: function (node, m, M) {
28069 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
28070 minOverlap = minArea = Infinity;
28071 for (i = m; i <= M - m; i++) {
28072 bbox1 = distBBox(node, 0, i, this.toBBox);
28073 bbox2 = distBBox(node, i, M, this.toBBox);
28074 overlap = intersectionArea(bbox1, bbox2);
28075 area = bboxArea(bbox1) + bboxArea(bbox2);
28076 if (overlap < minOverlap) {
28077 minOverlap = overlap;
28078 index = i;
28079 minArea = area < minArea ? area : minArea;
28080 } else if (overlap === minOverlap) {
28081 if (area < minArea) {
28082 minArea = area;
28083 index = i;
28084 }
28085 }
28086 }
28087 return index;
28088 },
28089 _chooseSplitAxis: function (node, m, M) {
28090 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
28091 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
28092 xMargin = this._allDistMargin(node, m, M, compareMinX),
28093 yMargin = this._allDistMargin(node, m, M, compareMinY);
28094 if (xMargin < yMargin) node.children.sort(compareMinX);
28095 },
28096 _allDistMargin: function (node, m, M, compare) {
28097 node.children.sort(compare);
28098 var toBBox = this.toBBox,
28099 leftBBox = distBBox(node, 0, m, toBBox),
28100 rightBBox = distBBox(node, M - m, M, toBBox),
28101 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
28102 i, child;
28103 for (i = m; i < M - m; i++) {
28104 child = node.children[i];
28105 extend(leftBBox, node.leaf ? toBBox(child) : child);
28106 margin += bboxMargin(leftBBox);
28107 }
28108 for (i = M - m - 1; i >= m; i--) {
28109 child = node.children[i];
28110 extend(rightBBox, node.leaf ? toBBox(child) : child);
28111 margin += bboxMargin(rightBBox);
28112 }
28113 return margin;
28114 },
28115 _adjustParentBBoxes: function (bbox, path, level) {
28116 for (var i = level; i >= 0; i--) {
28117 extend(path[i], bbox);
28118 }
28119 },
28120 _condense: function (path) {
28121 for (var i = path.length - 1, siblings; i >= 0; i--) {
28122 if (path[i].children.length === 0) {
28123 if (i > 0) {
28124 siblings = path[i - 1].children;
28125 siblings.splice(siblings.indexOf(path[i]), 1);
28126 } else this.clear();
28127 } else calcBBox(path[i], this.toBBox);
28128 }
28129 },
28130 _initFormat: function (format) {
28131 var compareArr = ['return a', ' - b', ';'];
28132 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
28133 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
28134 this.toBBox = new Function('a',
28135 'return {minX: a' + format[0] +
28136 ', minY: a' + format[1] +
28137 ', maxX: a' + format[2] +
28138 ', maxY: a' + format[3] + '};');
28139 }
28140};
28141function findItem(item, items, equalsFn) {
28142 if (!equalsFn) return items.indexOf(item);
28143 for (var i = 0; i < items.length; i++) {
28144 if (equalsFn(item, items[i])) return i;
28145 }
28146 return -1;
28147}
28148function calcBBox(node, toBBox) {
28149 distBBox(node, 0, node.children.length, toBBox, node);
28150}
28151function distBBox(node, k, p, toBBox, destNode) {
28152 if (!destNode) destNode = createNode(null);
28153 destNode.minX = Infinity;
28154 destNode.minY = Infinity;
28155 destNode.maxX = -Infinity;
28156 destNode.maxY = -Infinity;
28157 for (var i = k, child; i < p; i++) {
28158 child = node.children[i];
28159 extend(destNode, node.leaf ? toBBox(child) : child);
28160 }
28161 return destNode;
28162}
28163function extend(a, b) {
28164 a.minX = Math.min(a.minX, b.minX);
28165 a.minY = Math.min(a.minY, b.minY);
28166 a.maxX = Math.max(a.maxX, b.maxX);
28167 a.maxY = Math.max(a.maxY, b.maxY);
28168 return a;
28169}
28170function compareNodeMinX(a, b) { return a.minX - b.minX; }
28171function compareNodeMinY(a, b) { return a.minY - b.minY; }
28172function bboxArea(a) { return (a.maxX - a.minX) * (a.maxY - a.minY); }
28173function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
28174function enlargedArea(a, b) {
28175 return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
28176 (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
28177}
28178function intersectionArea(a, b) {
28179 var minX = Math.max(a.minX, b.minX),
28180 minY = Math.max(a.minY, b.minY),
28181 maxX = Math.min(a.maxX, b.maxX),
28182 maxY = Math.min(a.maxY, b.maxY);
28183 return Math.max(0, maxX - minX) *
28184 Math.max(0, maxY - minY);
28185}
28186function contains(a, b) {
28187 return a.minX <= b.minX &&
28188 a.minY <= b.minY &&
28189 b.maxX <= a.maxX &&
28190 b.maxY <= a.maxY;
28191}
28192function intersects(a, b) {
28193 return b.minX <= a.maxX &&
28194 b.minY <= a.maxY &&
28195 b.maxX >= a.minX &&
28196 b.maxY >= a.minY;
28197}
28198function createNode(children) {
28199 return {
28200 children: children,
28201 height: 1,
28202 leaf: true,
28203 minX: Infinity,
28204 minY: Infinity,
28205 maxX: -Infinity,
28206 maxY: -Infinity
28207 };
28208}
28209function multiSelect(arr, left, right, n, compare) {
28210 var stack = [left, right],
28211 mid;
28212 while (stack.length) {
28213 right = stack.pop();
28214 left = stack.pop();
28215 if (right - left <= n) continue;
28216 mid = left + Math.ceil((right - left) / n / 2) * n;
28217 index$2(arr, mid, left, right, compare);
28218 stack.push(left, mid, mid, right);
28219 }
28220}
28221
28222exports['default'] = index;
28223
28224}((this.rbush = this.rbush || {})));}).call(ol.ext);
28225ol.ext.rbush = ol.ext.rbush.default;
28226
28227goog.provide('ol.structs.RBush');
28228
28229goog.require('ol');
28230goog.require('ol.ext.rbush');
28231goog.require('ol.extent');
28232goog.require('ol.obj');
28233
28234
28235/**
28236 * Wrapper around the RBush by Vladimir Agafonkin.
28237 *
28238 * @constructor
28239 * @param {number=} opt_maxEntries Max entries.
28240 * @see https://github.com/mourner/rbush
28241 * @struct
28242 * @template T
28243 */
28244ol.structs.RBush = function(opt_maxEntries) {
28245
28246 /**
28247 * @private
28248 */
28249 this.rbush_ = ol.ext.rbush(opt_maxEntries);
28250
28251 /**
28252 * A mapping between the objects added to this rbush wrapper
28253 * and the objects that are actually added to the internal rbush.
28254 * @private
28255 * @type {Object.<number, ol.RBushEntry>}
28256 */
28257 this.items_ = {};
28258
28259};
28260
28261
28262/**
28263 * Insert a value into the RBush.
28264 * @param {ol.Extent} extent Extent.
28265 * @param {T} value Value.
28266 */
28267ol.structs.RBush.prototype.insert = function(extent, value) {
28268 /** @type {ol.RBushEntry} */
28269 var item = {
28270 minX: extent[0],
28271 minY: extent[1],
28272 maxX: extent[2],
28273 maxY: extent[3],
28274 value: value
28275 };
28276
28277 this.rbush_.insert(item);
28278 this.items_[ol.getUid(value)] = item;
28279};
28280
28281
28282/**
28283 * Bulk-insert values into the RBush.
28284 * @param {Array.<ol.Extent>} extents Extents.
28285 * @param {Array.<T>} values Values.
28286 */
28287ol.structs.RBush.prototype.load = function(extents, values) {
28288 var items = new Array(values.length);
28289 for (var i = 0, l = values.length; i < l; i++) {
28290 var extent = extents[i];
28291 var value = values[i];
28292
28293 /** @type {ol.RBushEntry} */
28294 var item = {
28295 minX: extent[0],
28296 minY: extent[1],
28297 maxX: extent[2],
28298 maxY: extent[3],
28299 value: value
28300 };
28301 items[i] = item;
28302 this.items_[ol.getUid(value)] = item;
28303 }
28304 this.rbush_.load(items);
28305};
28306
28307
28308/**
28309 * Remove a value from the RBush.
28310 * @param {T} value Value.
28311 * @return {boolean} Removed.
28312 */
28313ol.structs.RBush.prototype.remove = function(value) {
28314 var uid = ol.getUid(value);
28315
28316 // get the object in which the value was wrapped when adding to the
28317 // internal rbush. then use that object to do the removal.
28318 var item = this.items_[uid];
28319 delete this.items_[uid];
28320 return this.rbush_.remove(item) !== null;
28321};
28322
28323
28324/**
28325 * Update the extent of a value in the RBush.
28326 * @param {ol.Extent} extent Extent.
28327 * @param {T} value Value.
28328 */
28329ol.structs.RBush.prototype.update = function(extent, value) {
28330 var item = this.items_[ol.getUid(value)];
28331 var bbox = [item.minX, item.minY, item.maxX, item.maxY];
28332 if (!ol.extent.equals(bbox, extent)) {
28333 this.remove(value);
28334 this.insert(extent, value);
28335 }
28336};
28337
28338
28339/**
28340 * Return all values in the RBush.
28341 * @return {Array.<T>} All.
28342 */
28343ol.structs.RBush.prototype.getAll = function() {
28344 var items = this.rbush_.all();
28345 return items.map(function(item) {
28346 return item.value;
28347 });
28348};
28349
28350
28351/**
28352 * Return all values in the given extent.
28353 * @param {ol.Extent} extent Extent.
28354 * @return {Array.<T>} All in extent.
28355 */
28356ol.structs.RBush.prototype.getInExtent = function(extent) {
28357 /** @type {ol.RBushEntry} */
28358 var bbox = {
28359 minX: extent[0],
28360 minY: extent[1],
28361 maxX: extent[2],
28362 maxY: extent[3]
28363 };
28364 var items = this.rbush_.search(bbox);
28365 return items.map(function(item) {
28366 return item.value;
28367 });
28368};
28369
28370
28371/**
28372 * Calls a callback function with each value in the tree.
28373 * If the callback returns a truthy value, this value is returned without
28374 * checking the rest of the tree.
28375 * @param {function(this: S, T): *} callback Callback.
28376 * @param {S=} opt_this The object to use as `this` in `callback`.
28377 * @return {*} Callback return value.
28378 * @template S
28379 */
28380ol.structs.RBush.prototype.forEach = function(callback, opt_this) {
28381 return this.forEach_(this.getAll(), callback, opt_this);
28382};
28383
28384
28385/**
28386 * Calls a callback function with each value in the provided extent.
28387 * @param {ol.Extent} extent Extent.
28388 * @param {function(this: S, T): *} callback Callback.
28389 * @param {S=} opt_this The object to use as `this` in `callback`.
28390 * @return {*} Callback return value.
28391 * @template S
28392 */
28393ol.structs.RBush.prototype.forEachInExtent = function(extent, callback, opt_this) {
28394 return this.forEach_(this.getInExtent(extent), callback, opt_this);
28395};
28396
28397
28398/**
28399 * @param {Array.<T>} values Values.
28400 * @param {function(this: S, T): *} callback Callback.
28401 * @param {S=} opt_this The object to use as `this` in `callback`.
28402 * @private
28403 * @return {*} Callback return value.
28404 * @template S
28405 */
28406ol.structs.RBush.prototype.forEach_ = function(values, callback, opt_this) {
28407 var result;
28408 for (var i = 0, l = values.length; i < l; i++) {
28409 result = callback.call(opt_this, values[i]);
28410 if (result) {
28411 return result;
28412 }
28413 }
28414 return result;
28415};
28416
28417
28418/**
28419 * @return {boolean} Is empty.
28420 */
28421ol.structs.RBush.prototype.isEmpty = function() {
28422 return ol.obj.isEmpty(this.items_);
28423};
28424
28425
28426/**
28427 * Remove all values from the RBush.
28428 */
28429ol.structs.RBush.prototype.clear = function() {
28430 this.rbush_.clear();
28431 this.items_ = {};
28432};
28433
28434
28435/**
28436 * @param {ol.Extent=} opt_extent Extent.
28437 * @return {ol.Extent} Extent.
28438 */
28439ol.structs.RBush.prototype.getExtent = function(opt_extent) {
28440 // FIXME add getExtent() to rbush
28441 var data = this.rbush_.data;
28442 return ol.extent.createOrUpdate(data.minX, data.minY, data.maxX, data.maxY, opt_extent);
28443};
28444
28445
28446/**
28447 * @param {ol.structs.RBush} rbush R-Tree.
28448 */
28449ol.structs.RBush.prototype.concat = function(rbush) {
28450 this.rbush_.load(rbush.rbush_.all());
28451 for (var i in rbush.items_) {
28452 this.items_[i | 0] = rbush.items_[i | 0];
28453 }
28454};
28455
28456goog.provide('ol.render.webgl.PolygonReplay');
28457
28458goog.require('ol');
28459goog.require('ol.array');
28460goog.require('ol.color');
28461goog.require('ol.extent');
28462goog.require('ol.obj');
28463goog.require('ol.geom.flat.contains');
28464goog.require('ol.geom.flat.orient');
28465goog.require('ol.geom.flat.transform');
28466goog.require('ol.render.webgl.polygonreplay.defaultshader');
28467goog.require('ol.render.webgl.LineStringReplay');
28468goog.require('ol.render.webgl.Replay');
28469goog.require('ol.render.webgl');
28470goog.require('ol.style.Stroke');
28471goog.require('ol.structs.LinkedList');
28472goog.require('ol.structs.RBush');
28473goog.require('ol.webgl');
28474goog.require('ol.webgl.Buffer');
28475
28476
28477if (ol.ENABLE_WEBGL) {
28478
28479 /**
28480 * @constructor
28481 * @extends {ol.render.webgl.Replay}
28482 * @param {number} tolerance Tolerance.
28483 * @param {ol.Extent} maxExtent Max extent.
28484 * @struct
28485 */
28486 ol.render.webgl.PolygonReplay = function(tolerance, maxExtent) {
28487 ol.render.webgl.Replay.call(this, tolerance, maxExtent);
28488
28489 this.lineStringReplay = new ol.render.webgl.LineStringReplay(
28490 tolerance, maxExtent);
28491
28492 /**
28493 * @private
28494 * @type {ol.render.webgl.polygonreplay.defaultshader.Locations}
28495 */
28496 this.defaultLocations_ = null;
28497
28498 /**
28499 * @private
28500 * @type {Array.<Array.<number>>}
28501 */
28502 this.styles_ = [];
28503
28504 /**
28505 * @private
28506 * @type {Array.<number>}
28507 */
28508 this.styleIndices_ = [];
28509
28510 /**
28511 * @private
28512 * @type {{fillColor: (Array.<number>|null),
28513 * changed: boolean}|null}
28514 */
28515 this.state_ = {
28516 fillColor: null,
28517 changed: false
28518 };
28519
28520 };
28521 ol.inherits(ol.render.webgl.PolygonReplay, ol.render.webgl.Replay);
28522
28523
28524 /**
28525 * Draw one polygon.
28526 * @param {Array.<number>} flatCoordinates Flat coordinates.
28527 * @param {Array.<Array.<number>>} holeFlatCoordinates Hole flat coordinates.
28528 * @param {number} stride Stride.
28529 * @private
28530 */
28531 ol.render.webgl.PolygonReplay.prototype.drawCoordinates_ = function(
28532 flatCoordinates, holeFlatCoordinates, stride) {
28533 // Triangulate the polygon
28534 var outerRing = new ol.structs.LinkedList();
28535 var rtree = new ol.structs.RBush();
28536 // Initialize the outer ring
28537 this.processFlatCoordinates_(flatCoordinates, stride, outerRing, rtree, true);
28538 var maxCoords = this.getMaxCoords_(outerRing);
28539
28540 // Eliminate holes, if there are any
28541 if (holeFlatCoordinates.length) {
28542 var i, ii;
28543 var holeLists = [];
28544 for (i = 0, ii = holeFlatCoordinates.length; i < ii; ++i) {
28545 var holeList = {
28546 list: new ol.structs.LinkedList(),
28547 maxCoords: undefined,
28548 rtree: new ol.structs.RBush()
28549 };
28550 holeLists.push(holeList);
28551 this.processFlatCoordinates_(holeFlatCoordinates[i],
28552 stride, holeList.list, holeList.rtree, false);
28553 this.classifyPoints_(holeList.list, holeList.rtree, true);
28554 holeList.maxCoords = this.getMaxCoords_(holeList.list);
28555 }
28556 holeLists.sort(function(a, b) {
28557 return b.maxCoords[0] === a.maxCoords[0] ?
28558 a.maxCoords[1] - b.maxCoords[1] : b.maxCoords[0] - a.maxCoords[0];
28559 });
28560 for (i = 0; i < holeLists.length; ++i) {
28561 var currList = holeLists[i].list;
28562 var start = currList.firstItem();
28563 var currItem = start;
28564 var intersection;
28565 do {
28566 //TODO: Triangulate holes when they intersect the outer ring.
28567 if (this.getIntersections_(currItem, rtree).length) {
28568 intersection = true;
28569 break;
28570 }
28571 currItem = currList.nextItem();
28572 } while (start !== currItem);
28573 if (!intersection) {
28574 if (this.bridgeHole_(currList, holeLists[i].maxCoords[0], outerRing, maxCoords[0], rtree)) {
28575 rtree.concat(holeLists[i].rtree);
28576 this.classifyPoints_(outerRing, rtree, false);
28577 }
28578 }
28579 }
28580 } else {
28581 this.classifyPoints_(outerRing, rtree, false);
28582 }
28583 this.triangulate_(outerRing, rtree);
28584 };
28585
28586
28587 /**
28588 * Inserts flat coordinates in a linked list and adds them to the vertex buffer.
28589 * @private
28590 * @param {Array.<number>} flatCoordinates Flat coordinates.
28591 * @param {number} stride Stride.
28592 * @param {ol.structs.LinkedList} list Linked list.
28593 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28594 * @param {boolean} clockwise Coordinate order should be clockwise.
28595 */
28596 ol.render.webgl.PolygonReplay.prototype.processFlatCoordinates_ = function(
28597 flatCoordinates, stride, list, rtree, clockwise) {
28598 var isClockwise = ol.geom.flat.orient.linearRingIsClockwise(flatCoordinates,
28599 0, flatCoordinates.length, stride);
28600 var i, ii;
28601 var n = this.vertices.length / 2;
28602 /** @type {ol.WebglPolygonVertex} */
28603 var start;
28604 /** @type {ol.WebglPolygonVertex} */
28605 var p0;
28606 /** @type {ol.WebglPolygonVertex} */
28607 var p1;
28608 var extents = [];
28609 var segments = [];
28610 if (clockwise === isClockwise) {
28611 start = this.createPoint_(flatCoordinates[0], flatCoordinates[1], n++);
28612 p0 = start;
28613 for (i = stride, ii = flatCoordinates.length; i < ii; i += stride) {
28614 p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);
28615 segments.push(this.insertItem_(p0, p1, list));
28616 extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
28617 Math.max(p0.y, p1.y)]);
28618 p0 = p1;
28619 }
28620 segments.push(this.insertItem_(p1, start, list));
28621 extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
28622 Math.max(p0.y, p1.y)]);
28623 } else {
28624 var end = flatCoordinates.length - stride;
28625 start = this.createPoint_(flatCoordinates[end], flatCoordinates[end + 1], n++);
28626 p0 = start;
28627 for (i = end - stride, ii = 0; i >= ii; i -= stride) {
28628 p1 = this.createPoint_(flatCoordinates[i], flatCoordinates[i + 1], n++);
28629 segments.push(this.insertItem_(p0, p1, list));
28630 extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
28631 Math.max(p0.y, p1.y)]);
28632 p0 = p1;
28633 }
28634 segments.push(this.insertItem_(p1, start, list));
28635 extents.push([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y), Math.max(p0.x, p1.x),
28636 Math.max(p0.y, p1.y)]);
28637 }
28638 rtree.load(extents, segments);
28639 };
28640
28641
28642 /**
28643 * Returns the rightmost coordinates of a polygon on the X axis.
28644 * @private
28645 * @param {ol.structs.LinkedList} list Polygons ring.
28646 * @return {Array.<number>} Max X coordinates.
28647 */
28648 ol.render.webgl.PolygonReplay.prototype.getMaxCoords_ = function(list) {
28649 var start = list.firstItem();
28650 var seg = start;
28651 var maxCoords = [seg.p0.x, seg.p0.y];
28652
28653 do {
28654 seg = list.nextItem();
28655 if (seg.p0.x > maxCoords[0]) {
28656 maxCoords = [seg.p0.x, seg.p0.y];
28657 }
28658 } while (seg !== start);
28659
28660 return maxCoords;
28661 };
28662
28663
28664 /**
28665 * Classifies the points of a polygon list as convex, reflex. Removes collinear vertices.
28666 * @private
28667 * @param {ol.structs.LinkedList} list Polygon ring.
28668 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28669 * @param {boolean} ccw The orientation of the polygon is counter-clockwise.
28670 * @return {boolean} There were reclassified points.
28671 */
28672 ol.render.webgl.PolygonReplay.prototype.classifyPoints_ = function(list, rtree, ccw) {
28673 var start = list.firstItem();
28674 var s0 = start;
28675 var s1 = list.nextItem();
28676 var pointsReclassified = false;
28677 do {
28678 var reflex = ccw ? ol.render.webgl.triangleIsCounterClockwise(s1.p1.x,
28679 s1.p1.y, s0.p1.x, s0.p1.y, s0.p0.x, s0.p0.y) :
28680 ol.render.webgl.triangleIsCounterClockwise(s0.p0.x, s0.p0.y, s0.p1.x,
28681 s0.p1.y, s1.p1.x, s1.p1.y);
28682 if (reflex === undefined) {
28683 this.removeItem_(s0, s1, list, rtree);
28684 pointsReclassified = true;
28685 if (s1 === start) {
28686 start = list.getNextItem();
28687 }
28688 s1 = s0;
28689 list.prevItem();
28690 } else if (s0.p1.reflex !== reflex) {
28691 s0.p1.reflex = reflex;
28692 pointsReclassified = true;
28693 }
28694 s0 = s1;
28695 s1 = list.nextItem();
28696 } while (s0 !== start);
28697 return pointsReclassified;
28698 };
28699
28700
28701 /**
28702 * @private
28703 * @param {ol.structs.LinkedList} hole Linked list of the hole.
28704 * @param {number} holeMaxX Maximum X value of the hole.
28705 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28706 * @param {number} listMaxX Maximum X value of the polygon.
28707 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28708 * @return {boolean} Bridging was successful.
28709 */
28710 ol.render.webgl.PolygonReplay.prototype.bridgeHole_ = function(hole, holeMaxX,
28711 list, listMaxX, rtree) {
28712 var seg = hole.firstItem();
28713 while (seg.p1.x !== holeMaxX) {
28714 seg = hole.nextItem();
28715 }
28716
28717 var p1 = seg.p1;
28718 /** @type {ol.WebglPolygonVertex} */
28719 var p2 = {x: listMaxX, y: p1.y, i: -1};
28720 var minDist = Infinity;
28721 var i, ii, bestPoint;
28722 /** @type {ol.WebglPolygonVertex} */
28723 var p5;
28724
28725 var intersectingSegments = this.getIntersections_({p0: p1, p1: p2}, rtree, true);
28726 for (i = 0, ii = intersectingSegments.length; i < ii; ++i) {
28727 var currSeg = intersectingSegments[i];
28728 var intersection = this.calculateIntersection_(p1, p2, currSeg.p0,
28729 currSeg.p1, true);
28730 var dist = Math.abs(p1.x - intersection[0]);
28731 if (dist < minDist && ol.render.webgl.triangleIsCounterClockwise(p1.x, p1.y,
28732 currSeg.p0.x, currSeg.p0.y, currSeg.p1.x, currSeg.p1.y) !== undefined) {
28733 minDist = dist;
28734 p5 = {x: intersection[0], y: intersection[1], i: -1};
28735 seg = currSeg;
28736 }
28737 }
28738 if (minDist === Infinity) {
28739 return false;
28740 }
28741 bestPoint = seg.p1;
28742
28743 if (minDist > 0) {
28744 var pointsInTriangle = this.getPointsInTriangle_(p1, p5, seg.p1, rtree);
28745 if (pointsInTriangle.length) {
28746 var theta = Infinity;
28747 for (i = 0, ii = pointsInTriangle.length; i < ii; ++i) {
28748 var currPoint = pointsInTriangle[i];
28749 var currTheta = Math.atan2(p1.y - currPoint.y, p2.x - currPoint.x);
28750 if (currTheta < theta || (currTheta === theta && currPoint.x < bestPoint.x)) {
28751 theta = currTheta;
28752 bestPoint = currPoint;
28753 }
28754 }
28755 }
28756 }
28757
28758 seg = list.firstItem();
28759 while (seg.p1.x !== bestPoint.x || seg.p1.y !== bestPoint.y) {
28760 seg = list.nextItem();
28761 }
28762
28763 //We clone the bridge points as they can have different convexity.
28764 var p0Bridge = {x: p1.x, y: p1.y, i: p1.i, reflex: undefined};
28765 var p1Bridge = {x: seg.p1.x, y: seg.p1.y, i: seg.p1.i, reflex: undefined};
28766
28767 hole.getNextItem().p0 = p0Bridge;
28768 this.insertItem_(p1, seg.p1, hole, rtree);
28769 this.insertItem_(p1Bridge, p0Bridge, hole, rtree);
28770 seg.p1 = p1Bridge;
28771 hole.setFirstItem();
28772 list.concat(hole);
28773
28774 return true;
28775 };
28776
28777
28778 /**
28779 * @private
28780 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28781 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28782 */
28783 ol.render.webgl.PolygonReplay.prototype.triangulate_ = function(list, rtree) {
28784 var ccw = false;
28785 var simple = this.isSimple_(list, rtree);
28786
28787 // Start clipping ears
28788 while (list.getLength() > 3) {
28789 if (simple) {
28790 if (!this.clipEars_(list, rtree, simple, ccw)) {
28791 if (!this.classifyPoints_(list, rtree, ccw)) {
28792 // Due to the behavior of OL's PIP algorithm, the ear clipping cannot
28793 // introduce touching segments. However, the original data may have some.
28794 if (!this.resolveSelfIntersections_(list, rtree, true)) {
28795 break;
28796 }
28797 }
28798 }
28799 } else {
28800 if (!this.clipEars_(list, rtree, simple, ccw)) {
28801 // We ran out of ears, try to reclassify.
28802 if (!this.classifyPoints_(list, rtree, ccw)) {
28803 // We have a bad polygon, try to resolve local self-intersections.
28804 if (!this.resolveSelfIntersections_(list, rtree)) {
28805 simple = this.isSimple_(list, rtree);
28806 if (!simple) {
28807 // We have a really bad polygon, try more time consuming methods.
28808 this.splitPolygon_(list, rtree);
28809 break;
28810 } else {
28811 ccw = !this.isClockwise_(list);
28812 this.classifyPoints_(list, rtree, ccw);
28813 }
28814 }
28815 }
28816 }
28817 }
28818 }
28819 if (list.getLength() === 3) {
28820 var numIndices = this.indices.length;
28821 this.indices[numIndices++] = list.getPrevItem().p0.i;
28822 this.indices[numIndices++] = list.getCurrItem().p0.i;
28823 this.indices[numIndices++] = list.getNextItem().p0.i;
28824 }
28825 };
28826
28827
28828 /**
28829 * @private
28830 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28831 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28832 * @param {boolean} simple The polygon is simple.
28833 * @param {boolean} ccw Orientation of the polygon is counter-clockwise.
28834 * @return {boolean} There were processed ears.
28835 */
28836 ol.render.webgl.PolygonReplay.prototype.clipEars_ = function(list, rtree, simple, ccw) {
28837 var numIndices = this.indices.length;
28838 var start = list.firstItem();
28839 var s0 = list.getPrevItem();
28840 var s1 = start;
28841 var s2 = list.nextItem();
28842 var s3 = list.getNextItem();
28843 var p0, p1, p2;
28844 var processedEars = false;
28845 do {
28846 p0 = s1.p0;
28847 p1 = s1.p1;
28848 p2 = s2.p1;
28849 if (p1.reflex === false) {
28850 // We might have a valid ear
28851 var variableCriterion;
28852 if (simple) {
28853 variableCriterion = this.getPointsInTriangle_(p0, p1, p2, rtree, true).length === 0;
28854 } else {
28855 variableCriterion = ccw ? this.diagonalIsInside_(s3.p1, p2, p1, p0,
28856 s0.p0) : this.diagonalIsInside_(s0.p0, p0, p1, p2, s3.p1);
28857 }
28858 if ((simple || this.getIntersections_({p0: p0, p1: p2}, rtree).length === 0) &&
28859 variableCriterion) {
28860 //The diagonal is completely inside the polygon
28861 if (simple || p0.reflex === false || p2.reflex === false ||
28862 ol.geom.flat.orient.linearRingIsClockwise([s0.p0.x, s0.p0.y, p0.x,
28863 p0.y, p1.x, p1.y, p2.x, p2.y, s3.p1.x, s3.p1.y], 0, 10, 2) === !ccw) {
28864 //The diagonal is persumably valid, we have an ear
28865 this.indices[numIndices++] = p0.i;
28866 this.indices[numIndices++] = p1.i;
28867 this.indices[numIndices++] = p2.i;
28868 this.removeItem_(s1, s2, list, rtree);
28869 if (s2 === start) {
28870 start = s3;
28871 }
28872 processedEars = true;
28873 }
28874 }
28875 }
28876 // Else we have a reflex point.
28877 s0 = list.getPrevItem();
28878 s1 = list.getCurrItem();
28879 s2 = list.nextItem();
28880 s3 = list.getNextItem();
28881 } while (s1 !== start && list.getLength() > 3);
28882
28883 return processedEars;
28884 };
28885
28886
28887 /**
28888 * @private
28889 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28890 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28891 * @param {boolean=} opt_touch Resolve touching segments.
28892 * @return {boolean} There were resolved intersections.
28893 */
28894 ol.render.webgl.PolygonReplay.prototype.resolveSelfIntersections_ = function(
28895 list, rtree, opt_touch) {
28896 var start = list.firstItem();
28897 list.nextItem();
28898 var s0 = start;
28899 var s1 = list.nextItem();
28900 var resolvedIntersections = false;
28901
28902 do {
28903 var intersection = this.calculateIntersection_(s0.p0, s0.p1, s1.p0, s1.p1,
28904 opt_touch);
28905 if (intersection) {
28906 var breakCond = false;
28907 var numVertices = this.vertices.length;
28908 var numIndices = this.indices.length;
28909 var n = numVertices / 2;
28910 var seg = list.prevItem();
28911 list.removeItem();
28912 rtree.remove(seg);
28913 breakCond = (seg === start);
28914 var p;
28915 if (opt_touch) {
28916 if (intersection[0] === s0.p0.x && intersection[1] === s0.p0.y) {
28917 list.prevItem();
28918 p = s0.p0;
28919 s1.p0 = p;
28920 rtree.remove(s0);
28921 breakCond = breakCond || (s0 === start);
28922 } else {
28923 p = s1.p1;
28924 s0.p1 = p;
28925 rtree.remove(s1);
28926 breakCond = breakCond || (s1 === start);
28927 }
28928 list.removeItem();
28929 } else {
28930 p = this.createPoint_(intersection[0], intersection[1], n);
28931 s0.p1 = p;
28932 s1.p0 = p;
28933 rtree.update([Math.min(s0.p0.x, s0.p1.x), Math.min(s0.p0.y, s0.p1.y),
28934 Math.max(s0.p0.x, s0.p1.x), Math.max(s0.p0.y, s0.p1.y)], s0);
28935 rtree.update([Math.min(s1.p0.x, s1.p1.x), Math.min(s1.p0.y, s1.p1.y),
28936 Math.max(s1.p0.x, s1.p1.x), Math.max(s1.p0.y, s1.p1.y)], s1);
28937 }
28938
28939 this.indices[numIndices++] = seg.p0.i;
28940 this.indices[numIndices++] = seg.p1.i;
28941 this.indices[numIndices++] = p.i;
28942
28943 resolvedIntersections = true;
28944 if (breakCond) {
28945 break;
28946 }
28947 }
28948
28949 s0 = list.getPrevItem();
28950 s1 = list.nextItem();
28951 } while (s0 !== start);
28952 return resolvedIntersections;
28953 };
28954
28955
28956 /**
28957 * @private
28958 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28959 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28960 * @return {boolean} The polygon is simple.
28961 */
28962 ol.render.webgl.PolygonReplay.prototype.isSimple_ = function(list, rtree) {
28963 var start = list.firstItem();
28964 var seg = start;
28965 do {
28966 if (this.getIntersections_(seg, rtree).length) {
28967 return false;
28968 }
28969 seg = list.nextItem();
28970 } while (seg !== start);
28971 return true;
28972 };
28973
28974
28975 /**
28976 * @private
28977 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28978 * @return {boolean} Orientation is clockwise.
28979 */
28980 ol.render.webgl.PolygonReplay.prototype.isClockwise_ = function(list) {
28981 var length = list.getLength() * 2;
28982 var flatCoordinates = new Array(length);
28983 var start = list.firstItem();
28984 var seg = start;
28985 var i = 0;
28986 do {
28987 flatCoordinates[i++] = seg.p0.x;
28988 flatCoordinates[i++] = seg.p0.y;
28989 seg = list.nextItem();
28990 } while (seg !== start);
28991 return ol.geom.flat.orient.linearRingIsClockwise(flatCoordinates, 0, length, 2);
28992 };
28993
28994
28995 /**
28996 * @private
28997 * @param {ol.structs.LinkedList} list Linked list of the polygon.
28998 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
28999 */
29000 ol.render.webgl.PolygonReplay.prototype.splitPolygon_ = function(list, rtree) {
29001 var start = list.firstItem();
29002 var s0 = start;
29003 do {
29004 var intersections = this.getIntersections_(s0, rtree);
29005 if (intersections.length) {
29006 var s1 = intersections[0];
29007 var n = this.vertices.length / 2;
29008 var intersection = this.calculateIntersection_(s0.p0,
29009 s0.p1, s1.p0, s1.p1);
29010 var p = this.createPoint_(intersection[0], intersection[1], n);
29011 var newPolygon = new ol.structs.LinkedList();
29012 var newRtree = new ol.structs.RBush();
29013 this.insertItem_(p, s0.p1, newPolygon, newRtree);
29014 s0.p1 = p;
29015 rtree.update([Math.min(s0.p0.x, p.x), Math.min(s0.p0.y, p.y),
29016 Math.max(s0.p0.x, p.x), Math.max(s0.p0.y, p.y)], s0);
29017 var currItem = list.nextItem();
29018 while (currItem !== s1) {
29019 this.insertItem_(currItem.p0, currItem.p1, newPolygon, newRtree);
29020 rtree.remove(currItem);
29021 list.removeItem();
29022 currItem = list.getCurrItem();
29023 }
29024 this.insertItem_(s1.p0, p, newPolygon, newRtree);
29025 s1.p0 = p;
29026 rtree.update([Math.min(s1.p1.x, p.x), Math.min(s1.p1.y, p.y),
29027 Math.max(s1.p1.x, p.x), Math.max(s1.p1.y, p.y)], s1);
29028 this.classifyPoints_(list, rtree, false);
29029 this.triangulate_(list, rtree);
29030 this.classifyPoints_(newPolygon, newRtree, false);
29031 this.triangulate_(newPolygon, newRtree);
29032 break;
29033 }
29034 s0 = list.nextItem();
29035 } while (s0 !== start);
29036 };
29037
29038
29039 /**
29040 * @private
29041 * @param {number} x X coordinate.
29042 * @param {number} y Y coordinate.
29043 * @param {number} i Index.
29044 * @return {ol.WebglPolygonVertex} List item.
29045 */
29046 ol.render.webgl.PolygonReplay.prototype.createPoint_ = function(x, y, i) {
29047 var numVertices = this.vertices.length;
29048 this.vertices[numVertices++] = x;
29049 this.vertices[numVertices++] = y;
29050 /** @type {ol.WebglPolygonVertex} */
29051 var p = {
29052 x: x,
29053 y: y,
29054 i: i,
29055 reflex: undefined
29056 };
29057 return p;
29058 };
29059
29060
29061 /**
29062 * @private
29063 * @param {ol.WebglPolygonVertex} p0 First point of segment.
29064 * @param {ol.WebglPolygonVertex} p1 Second point of segment.
29065 * @param {ol.structs.LinkedList} list Polygon ring.
29066 * @param {ol.structs.RBush=} opt_rtree Insert the segment into the R-Tree.
29067 * @return {ol.WebglPolygonSegment} segment.
29068 */
29069 ol.render.webgl.PolygonReplay.prototype.insertItem_ = function(p0, p1, list, opt_rtree) {
29070 var seg = {
29071 p0: p0,
29072 p1: p1
29073 };
29074 list.insertItem(seg);
29075 if (opt_rtree) {
29076 opt_rtree.insert([Math.min(p0.x, p1.x), Math.min(p0.y, p1.y),
29077 Math.max(p0.x, p1.x), Math.max(p0.y, p1.y)], seg);
29078 }
29079 return seg;
29080 };
29081
29082
29083 /**
29084 * @private
29085 * @param {ol.WebglPolygonSegment} s0 Segment before the remove candidate.
29086 * @param {ol.WebglPolygonSegment} s1 Remove candidate segment.
29087 * @param {ol.structs.LinkedList} list Polygon ring.
29088 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
29089 */
29090 ol.render.webgl.PolygonReplay.prototype.removeItem_ = function(s0, s1, list, rtree) {
29091 if (list.getCurrItem() === s1) {
29092 list.removeItem();
29093 s0.p1 = s1.p1;
29094 rtree.remove(s1);
29095 rtree.update([Math.min(s0.p0.x, s0.p1.x), Math.min(s0.p0.y, s0.p1.y),
29096 Math.max(s0.p0.x, s0.p1.x), Math.max(s0.p0.y, s0.p1.y)], s0);
29097 }
29098 };
29099
29100
29101 /**
29102 * @private
29103 * @param {ol.WebglPolygonVertex} p0 First point.
29104 * @param {ol.WebglPolygonVertex} p1 Second point.
29105 * @param {ol.WebglPolygonVertex} p2 Third point.
29106 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
29107 * @param {boolean=} opt_reflex Only include reflex points.
29108 * @return {Array.<ol.WebglPolygonVertex>} Points in the triangle.
29109 */
29110 ol.render.webgl.PolygonReplay.prototype.getPointsInTriangle_ = function(p0, p1,
29111 p2, rtree, opt_reflex) {
29112 var i, ii, j, p;
29113 var result = [];
29114 var segmentsInExtent = rtree.getInExtent([Math.min(p0.x, p1.x, p2.x),
29115 Math.min(p0.y, p1.y, p2.y), Math.max(p0.x, p1.x, p2.x), Math.max(p0.y,
29116 p1.y, p2.y)]);
29117 for (i = 0, ii = segmentsInExtent.length; i < ii; ++i) {
29118 for (j in segmentsInExtent[i]) {
29119 p = segmentsInExtent[i][j];
29120 if (typeof p === 'object' && (!opt_reflex || p.reflex)) {
29121 if ((p.x !== p0.x || p.y !== p0.y) && (p.x !== p1.x || p.y !== p1.y) &&
29122 (p.x !== p2.x || p.y !== p2.y) && result.indexOf(p) === -1 &&
29123 ol.geom.flat.contains.linearRingContainsXY([p0.x, p0.y, p1.x, p1.y,
29124 p2.x, p2.y], 0, 6, 2, p.x, p.y)) {
29125 result.push(p);
29126 }
29127 }
29128 }
29129 }
29130 return result;
29131 };
29132
29133
29134 /**
29135 * @private
29136 * @param {ol.WebglPolygonSegment} segment Segment.
29137 * @param {ol.structs.RBush} rtree R-Tree of the polygon.
29138 * @param {boolean=} opt_touch Touching segments should be considered an intersection.
29139 * @return {Array.<ol.WebglPolygonSegment>} Intersecting segments.
29140 */
29141 ol.render.webgl.PolygonReplay.prototype.getIntersections_ = function(segment, rtree, opt_touch) {
29142 var p0 = segment.p0;
29143 var p1 = segment.p1;
29144 var segmentsInExtent = rtree.getInExtent([Math.min(p0.x, p1.x),
29145 Math.min(p0.y, p1.y), Math.max(p0.x, p1.x), Math.max(p0.y, p1.y)]);
29146 var result = [];
29147 var i, ii;
29148 for (i = 0, ii = segmentsInExtent.length; i < ii; ++i) {
29149 var currSeg = segmentsInExtent[i];
29150 if (segment !== currSeg && (opt_touch || currSeg.p0 !== p1 || currSeg.p1 !== p0) &&
29151 this.calculateIntersection_(p0, p1, currSeg.p0, currSeg.p1, opt_touch)) {
29152 result.push(currSeg);
29153 }
29154 }
29155 return result;
29156 };
29157
29158
29159 /**
29160 * Line intersection algorithm by Paul Bourke.
29161 * @see http://paulbourke.net/geometry/pointlineplane/
29162 *
29163 * @private
29164 * @param {ol.WebglPolygonVertex} p0 First point.
29165 * @param {ol.WebglPolygonVertex} p1 Second point.
29166 * @param {ol.WebglPolygonVertex} p2 Third point.
29167 * @param {ol.WebglPolygonVertex} p3 Fourth point.
29168 * @param {boolean=} opt_touch Touching segments should be considered an intersection.
29169 * @return {Array.<number>|undefined} Intersection coordinates.
29170 */
29171 ol.render.webgl.PolygonReplay.prototype.calculateIntersection_ = function(p0,
29172 p1, p2, p3, opt_touch) {
29173 var denom = (p3.y - p2.y) * (p1.x - p0.x) - (p3.x - p2.x) * (p1.y - p0.y);
29174 if (denom !== 0) {
29175 var ua = ((p3.x - p2.x) * (p0.y - p2.y) - (p3.y - p2.y) * (p0.x - p2.x)) / denom;
29176 var ub = ((p1.x - p0.x) * (p0.y - p2.y) - (p1.y - p0.y) * (p0.x - p2.x)) / denom;
29177 if ((!opt_touch && ua > ol.render.webgl.EPSILON && ua < 1 - ol.render.webgl.EPSILON &&
29178 ub > ol.render.webgl.EPSILON && ub < 1 - ol.render.webgl.EPSILON) || (opt_touch &&
29179 ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)) {
29180 return [p0.x + ua * (p1.x - p0.x), p0.y + ua * (p1.y - p0.y)];
29181 }
29182 }
29183 return undefined;
29184 };
29185
29186
29187 /**
29188 * @private
29189 * @param {ol.WebglPolygonVertex} p0 Point before the start of the diagonal.
29190 * @param {ol.WebglPolygonVertex} p1 Start point of the diagonal.
29191 * @param {ol.WebglPolygonVertex} p2 Ear candidate.
29192 * @param {ol.WebglPolygonVertex} p3 End point of the diagonal.
29193 * @param {ol.WebglPolygonVertex} p4 Point after the end of the diagonal.
29194 * @return {boolean} Diagonal is inside the polygon.
29195 */
29196 ol.render.webgl.PolygonReplay.prototype.diagonalIsInside_ = function(p0, p1, p2, p3, p4) {
29197 if (p1.reflex === undefined || p3.reflex === undefined) {
29198 return false;
29199 }
29200 var p1IsLeftOf = (p2.x - p3.x) * (p1.y - p3.y) > (p2.y - p3.y) * (p1.x - p3.x);
29201 var p1IsRightOf = (p4.x - p3.x) * (p1.y - p3.y) < (p4.y - p3.y) * (p1.x - p3.x);
29202 var p3IsLeftOf = (p0.x - p1.x) * (p3.y - p1.y) > (p0.y - p1.y) * (p3.x - p1.x);
29203 var p3IsRightOf = (p2.x - p1.x) * (p3.y - p1.y) < (p2.y - p1.y) * (p3.x - p1.x);
29204 var p1InCone = p3.reflex ? p1IsRightOf || p1IsLeftOf : p1IsRightOf && p1IsLeftOf;
29205 var p3InCone = p1.reflex ? p3IsRightOf || p3IsLeftOf : p3IsRightOf && p3IsLeftOf;
29206 return p1InCone && p3InCone;
29207 };
29208
29209
29210 /**
29211 * @inheritDoc
29212 */
29213 ol.render.webgl.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
29214 var endss = multiPolygonGeometry.getEndss();
29215 var stride = multiPolygonGeometry.getStride();
29216 var currIndex = this.indices.length;
29217 var currLineIndex = this.lineStringReplay.getCurrentIndex();
29218 var flatCoordinates = multiPolygonGeometry.getFlatCoordinates();
29219 var i, ii, j, jj;
29220 var start = 0;
29221 for (i = 0, ii = endss.length; i < ii; ++i) {
29222 var ends = endss[i];
29223 if (ends.length > 0) {
29224 var outerRing = ol.geom.flat.transform.translate(flatCoordinates, start, ends[0],
29225 stride, -this.origin[0], -this.origin[1]);
29226 if (outerRing.length) {
29227 var holes = [];
29228 var holeFlatCoords;
29229 for (j = 1, jj = ends.length; j < jj; ++j) {
29230 if (ends[j] !== ends[j - 1]) {
29231 holeFlatCoords = ol.geom.flat.transform.translate(flatCoordinates, ends[j - 1],
29232 ends[j], stride, -this.origin[0], -this.origin[1]);
29233 holes.push(holeFlatCoords);
29234 }
29235 }
29236 this.lineStringReplay.drawPolygonCoordinates(outerRing, holes, stride);
29237 this.drawCoordinates_(outerRing, holes, stride);
29238 }
29239 }
29240 start = ends[ends.length - 1];
29241 }
29242 if (this.indices.length > currIndex) {
29243 this.startIndices.push(currIndex);
29244 this.startIndicesFeature.push(feature);
29245 if (this.state_.changed) {
29246 this.styleIndices_.push(currIndex);
29247 this.state_.changed = false;
29248 }
29249 }
29250 if (this.lineStringReplay.getCurrentIndex() > currLineIndex) {
29251 this.lineStringReplay.setPolygonStyle(feature, currLineIndex);
29252 }
29253 };
29254
29255
29256 /**
29257 * @inheritDoc
29258 */
29259 ol.render.webgl.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
29260 var ends = polygonGeometry.getEnds();
29261 var stride = polygonGeometry.getStride();
29262 if (ends.length > 0) {
29263 var flatCoordinates = polygonGeometry.getFlatCoordinates().map(Number);
29264 var outerRing = ol.geom.flat.transform.translate(flatCoordinates, 0, ends[0],
29265 stride, -this.origin[0], -this.origin[1]);
29266 if (outerRing.length) {
29267 var holes = [];
29268 var i, ii, holeFlatCoords;
29269 for (i = 1, ii = ends.length; i < ii; ++i) {
29270 if (ends[i] !== ends[i - 1]) {
29271 holeFlatCoords = ol.geom.flat.transform.translate(flatCoordinates, ends[i - 1],
29272 ends[i], stride, -this.origin[0], -this.origin[1]);
29273 holes.push(holeFlatCoords);
29274 }
29275 }
29276
29277 this.startIndices.push(this.indices.length);
29278 this.startIndicesFeature.push(feature);
29279 if (this.state_.changed) {
29280 this.styleIndices_.push(this.indices.length);
29281 this.state_.changed = false;
29282 }
29283 this.lineStringReplay.setPolygonStyle(feature);
29284
29285 this.lineStringReplay.drawPolygonCoordinates(outerRing, holes, stride);
29286 this.drawCoordinates_(outerRing, holes, stride);
29287 }
29288 }
29289 };
29290
29291
29292 /**
29293 * @inheritDoc
29294 **/
29295 ol.render.webgl.PolygonReplay.prototype.finish = function(context) {
29296 // create, bind, and populate the vertices buffer
29297 this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
29298
29299 // create, bind, and populate the indices buffer
29300 this.indicesBuffer = new ol.webgl.Buffer(this.indices);
29301
29302 this.startIndices.push(this.indices.length);
29303
29304 this.lineStringReplay.finish(context);
29305
29306 //Clean up, if there is nothing to draw
29307 if (this.styleIndices_.length === 0 && this.styles_.length > 0) {
29308 this.styles_ = [];
29309 }
29310
29311 this.vertices = null;
29312 this.indices = null;
29313 };
29314
29315
29316 /**
29317 * @inheritDoc
29318 */
29319 ol.render.webgl.PolygonReplay.prototype.getDeleteResourcesFunction = function(context) {
29320 var verticesBuffer = this.verticesBuffer;
29321 var indicesBuffer = this.indicesBuffer;
29322 var lineDeleter = this.lineStringReplay.getDeleteResourcesFunction(context);
29323 return function() {
29324 context.deleteBuffer(verticesBuffer);
29325 context.deleteBuffer(indicesBuffer);
29326 lineDeleter();
29327 };
29328 };
29329
29330
29331 /**
29332 * @inheritDoc
29333 */
29334 ol.render.webgl.PolygonReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {
29335 // get the program
29336 var fragmentShader, vertexShader;
29337 fragmentShader = ol.render.webgl.polygonreplay.defaultshader.fragment;
29338 vertexShader = ol.render.webgl.polygonreplay.defaultshader.vertex;
29339 var program = context.getProgram(fragmentShader, vertexShader);
29340
29341 // get the locations
29342 var locations;
29343 if (!this.defaultLocations_) {
29344 // eslint-disable-next-line openlayers-internal/no-missing-requires
29345 locations = new ol.render.webgl.polygonreplay.defaultshader.Locations(gl, program);
29346 this.defaultLocations_ = locations;
29347 } else {
29348 locations = this.defaultLocations_;
29349 }
29350
29351 context.useProgram(program);
29352
29353 // enable the vertex attrib arrays
29354 gl.enableVertexAttribArray(locations.a_position);
29355 gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,
29356 false, 8, 0);
29357
29358 return locations;
29359 };
29360
29361
29362 /**
29363 * @inheritDoc
29364 */
29365 ol.render.webgl.PolygonReplay.prototype.shutDownProgram = function(gl, locations) {
29366 gl.disableVertexAttribArray(locations.a_position);
29367 };
29368
29369
29370 /**
29371 * @inheritDoc
29372 */
29373 ol.render.webgl.PolygonReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {
29374 //Save GL parameters.
29375 var tmpDepthFunc = /** @type {number} */ (gl.getParameter(gl.DEPTH_FUNC));
29376 var tmpDepthMask = /** @type {boolean} */ (gl.getParameter(gl.DEPTH_WRITEMASK));
29377
29378 if (!hitDetection) {
29379 gl.enable(gl.DEPTH_TEST);
29380 gl.depthMask(true);
29381 gl.depthFunc(gl.NOTEQUAL);
29382 }
29383
29384 if (!ol.obj.isEmpty(skippedFeaturesHash)) {
29385 this.drawReplaySkipping_(gl, context, skippedFeaturesHash);
29386 } else {
29387 //Draw by style groups to minimize drawElements() calls.
29388 var i, start, end, nextStyle;
29389 end = this.startIndices[this.startIndices.length - 1];
29390 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
29391 start = this.styleIndices_[i];
29392 nextStyle = this.styles_[i];
29393 this.setFillStyle_(gl, nextStyle);
29394 this.drawElements(gl, context, start, end);
29395 end = start;
29396 }
29397 }
29398 if (!hitDetection) {
29399 gl.disable(gl.DEPTH_TEST);
29400 gl.clear(gl.DEPTH_BUFFER_BIT);
29401 //Restore GL parameters.
29402 gl.depthMask(tmpDepthMask);
29403 gl.depthFunc(tmpDepthFunc);
29404 }
29405 };
29406
29407
29408 /**
29409 * @inheritDoc
29410 */
29411 ol.render.webgl.PolygonReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,
29412 featureCallback, opt_hitExtent) {
29413 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;
29414 featureIndex = this.startIndices.length - 2;
29415 end = this.startIndices[featureIndex + 1];
29416 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
29417 nextStyle = this.styles_[i];
29418 this.setFillStyle_(gl, nextStyle);
29419 groupStart = this.styleIndices_[i];
29420
29421 while (featureIndex >= 0 &&
29422 this.startIndices[featureIndex] >= groupStart) {
29423 start = this.startIndices[featureIndex];
29424 feature = this.startIndicesFeature[featureIndex];
29425 featureUid = ol.getUid(feature).toString();
29426
29427 if (skippedFeaturesHash[featureUid] === undefined &&
29428 feature.getGeometry() &&
29429 (opt_hitExtent === undefined || ol.extent.intersects(
29430 /** @type {Array<number>} */ (opt_hitExtent),
29431 feature.getGeometry().getExtent()))) {
29432 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
29433 this.drawElements(gl, context, start, end);
29434
29435 var result = featureCallback(feature);
29436
29437 if (result) {
29438 return result;
29439 }
29440
29441 }
29442 featureIndex--;
29443 end = start;
29444 }
29445 }
29446 return undefined;
29447 };
29448
29449
29450 /**
29451 * @private
29452 * @param {WebGLRenderingContext} gl gl.
29453 * @param {ol.webgl.Context} context Context.
29454 * @param {Object} skippedFeaturesHash Ids of features to skip.
29455 */
29456 ol.render.webgl.PolygonReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {
29457 var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;
29458 featureIndex = this.startIndices.length - 2;
29459 end = start = this.startIndices[featureIndex + 1];
29460 for (i = this.styleIndices_.length - 1; i >= 0; --i) {
29461 nextStyle = this.styles_[i];
29462 this.setFillStyle_(gl, nextStyle);
29463 groupStart = this.styleIndices_[i];
29464
29465 while (featureIndex >= 0 &&
29466 this.startIndices[featureIndex] >= groupStart) {
29467 featureStart = this.startIndices[featureIndex];
29468 feature = this.startIndicesFeature[featureIndex];
29469 featureUid = ol.getUid(feature).toString();
29470
29471 if (skippedFeaturesHash[featureUid]) {
29472 if (start !== end) {
29473 this.drawElements(gl, context, start, end);
29474 gl.clear(gl.DEPTH_BUFFER_BIT);
29475 }
29476 end = featureStart;
29477 }
29478 featureIndex--;
29479 start = featureStart;
29480 }
29481 if (start !== end) {
29482 this.drawElements(gl, context, start, end);
29483 gl.clear(gl.DEPTH_BUFFER_BIT);
29484 }
29485 start = end = groupStart;
29486 }
29487 };
29488
29489
29490 /**
29491 * @private
29492 * @param {WebGLRenderingContext} gl gl.
29493 * @param {Array.<number>} color Color.
29494 */
29495 ol.render.webgl.PolygonReplay.prototype.setFillStyle_ = function(gl, color) {
29496 gl.uniform4fv(this.defaultLocations_.u_color, color);
29497 };
29498
29499
29500 /**
29501 * @inheritDoc
29502 */
29503 ol.render.webgl.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
29504 var fillStyleColor = fillStyle ? fillStyle.getColor() : [0, 0, 0, 0];
29505 if (!(fillStyleColor instanceof CanvasGradient) &&
29506 !(fillStyleColor instanceof CanvasPattern)) {
29507 fillStyleColor = ol.color.asArray(fillStyleColor).map(function(c, i) {
29508 return i != 3 ? c / 255 : c;
29509 }) || ol.render.webgl.defaultFillStyle;
29510 } else {
29511 fillStyleColor = ol.render.webgl.defaultFillStyle;
29512 }
29513 if (!this.state_.fillColor || !ol.array.equals(fillStyleColor, this.state_.fillColor)) {
29514 this.state_.fillColor = fillStyleColor;
29515 this.state_.changed = true;
29516 this.styles_.push(fillStyleColor);
29517 }
29518 //Provide a null stroke style, if no strokeStyle is provided. Required for the draw interaction to work.
29519 if (strokeStyle) {
29520 this.lineStringReplay.setFillStrokeStyle(null, strokeStyle);
29521 } else {
29522 var nullStrokeStyle = new ol.style.Stroke({
29523 color: [0, 0, 0, 0],
29524 lineWidth: 0
29525 });
29526 this.lineStringReplay.setFillStrokeStyle(null, nullStrokeStyle);
29527 }
29528 };
29529
29530}
29531
29532goog.provide('ol.style.Atlas');
29533
29534goog.require('ol.dom');
29535
29536
29537/**
29538 * This class facilitates the creation of image atlases.
29539 *
29540 * Images added to an atlas will be rendered onto a single
29541 * atlas canvas. The distribution of images on the canvas is
29542 * managed with the bin packing algorithm described in:
29543 * http://www.blackpawn.com/texts/lightmaps/
29544 *
29545 * @constructor
29546 * @struct
29547 * @param {number} size The size in pixels of the sprite image.
29548 * @param {number} space The space in pixels between images.
29549 * Because texture coordinates are float values, the edges of
29550 * images might not be completely correct (in a way that the
29551 * edges overlap when being rendered). To avoid this we add a
29552 * padding around each image.
29553 */
29554ol.style.Atlas = function(size, space) {
29555
29556 /**
29557 * @private
29558 * @type {number}
29559 */
29560 this.space_ = space;
29561
29562 /**
29563 * @private
29564 * @type {Array.<ol.AtlasBlock>}
29565 */
29566 this.emptyBlocks_ = [{x: 0, y: 0, width: size, height: size}];
29567
29568 /**
29569 * @private
29570 * @type {Object.<string, ol.AtlasInfo>}
29571 */
29572 this.entries_ = {};
29573
29574 /**
29575 * @private
29576 * @type {CanvasRenderingContext2D}
29577 */
29578 this.context_ = ol.dom.createCanvasContext2D(size, size);
29579
29580 /**
29581 * @private
29582 * @type {HTMLCanvasElement}
29583 */
29584 this.canvas_ = this.context_.canvas;
29585};
29586
29587
29588/**
29589 * @param {string} id The identifier of the entry to check.
29590 * @return {?ol.AtlasInfo} The atlas info.
29591 */
29592ol.style.Atlas.prototype.get = function(id) {
29593 return this.entries_[id] || null;
29594};
29595
29596
29597/**
29598 * @param {string} id The identifier of the entry to add.
29599 * @param {number} width The width.
29600 * @param {number} height The height.
29601 * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
29602 * Called to render the new image onto an atlas image.
29603 * @param {Object=} opt_this Value to use as `this` when executing
29604 * `renderCallback`.
29605 * @return {?ol.AtlasInfo} The position and atlas image for the entry.
29606 */
29607ol.style.Atlas.prototype.add = function(id, width, height, renderCallback, opt_this) {
29608 var block, i, ii;
29609 for (i = 0, ii = this.emptyBlocks_.length; i < ii; ++i) {
29610 block = this.emptyBlocks_[i];
29611 if (block.width >= width + this.space_ &&
29612 block.height >= height + this.space_) {
29613 // we found a block that is big enough for our entry
29614 var entry = {
29615 offsetX: block.x + this.space_,
29616 offsetY: block.y + this.space_,
29617 image: this.canvas_
29618 };
29619 this.entries_[id] = entry;
29620
29621 // render the image on the atlas image
29622 renderCallback.call(opt_this, this.context_,
29623 block.x + this.space_, block.y + this.space_);
29624
29625 // split the block after the insertion, either horizontally or vertically
29626 this.split_(i, block, width + this.space_, height + this.space_);
29627
29628 return entry;
29629 }
29630 }
29631
29632 // there is no space for the new entry in this atlas
29633 return null;
29634};
29635
29636
29637/**
29638 * @private
29639 * @param {number} index The index of the block.
29640 * @param {ol.AtlasBlock} block The block to split.
29641 * @param {number} width The width of the entry to insert.
29642 * @param {number} height The height of the entry to insert.
29643 */
29644ol.style.Atlas.prototype.split_ = function(index, block, width, height) {
29645 var deltaWidth = block.width - width;
29646 var deltaHeight = block.height - height;
29647
29648 /** @type {ol.AtlasBlock} */
29649 var newBlock1;
29650 /** @type {ol.AtlasBlock} */
29651 var newBlock2;
29652
29653 if (deltaWidth > deltaHeight) {
29654 // split vertically
29655 // block right of the inserted entry
29656 newBlock1 = {
29657 x: block.x + width,
29658 y: block.y,
29659 width: block.width - width,
29660 height: block.height
29661 };
29662
29663 // block below the inserted entry
29664 newBlock2 = {
29665 x: block.x,
29666 y: block.y + height,
29667 width: width,
29668 height: block.height - height
29669 };
29670 this.updateBlocks_(index, newBlock1, newBlock2);
29671 } else {
29672 // split horizontally
29673 // block right of the inserted entry
29674 newBlock1 = {
29675 x: block.x + width,
29676 y: block.y,
29677 width: block.width - width,
29678 height: height
29679 };
29680
29681 // block below the inserted entry
29682 newBlock2 = {
29683 x: block.x,
29684 y: block.y + height,
29685 width: block.width,
29686 height: block.height - height
29687 };
29688 this.updateBlocks_(index, newBlock1, newBlock2);
29689 }
29690};
29691
29692
29693/**
29694 * Remove the old block and insert new blocks at the same array position.
29695 * The new blocks are inserted at the same position, so that splitted
29696 * blocks (that are potentially smaller) are filled first.
29697 * @private
29698 * @param {number} index The index of the block to remove.
29699 * @param {ol.AtlasBlock} newBlock1 The 1st block to add.
29700 * @param {ol.AtlasBlock} newBlock2 The 2nd block to add.
29701 */
29702ol.style.Atlas.prototype.updateBlocks_ = function(index, newBlock1, newBlock2) {
29703 var args = [index, 1];
29704 if (newBlock1.width > 0 && newBlock1.height > 0) {
29705 args.push(newBlock1);
29706 }
29707 if (newBlock2.width > 0 && newBlock2.height > 0) {
29708 args.push(newBlock2);
29709 }
29710 this.emptyBlocks_.splice.apply(this.emptyBlocks_, args);
29711};
29712
29713goog.provide('ol.style.AtlasManager');
29714
29715goog.require('ol');
29716goog.require('ol.style.Atlas');
29717
29718
29719/**
29720 * Manages the creation of image atlases.
29721 *
29722 * Images added to this manager will be inserted into an atlas, which
29723 * will be used for rendering.
29724 * The `size` given in the constructor is the size for the first
29725 * atlas. After that, when new atlases are created, they will have
29726 * twice the size as the latest atlas (until `maxSize` is reached).
29727 *
29728 * If an application uses many images or very large images, it is recommended
29729 * to set a higher `size` value to avoid the creation of too many atlases.
29730 *
29731 * @constructor
29732 * @struct
29733 * @api
29734 * @param {olx.style.AtlasManagerOptions=} opt_options Options.
29735 */
29736ol.style.AtlasManager = function(opt_options) {
29737
29738 var options = opt_options || {};
29739
29740 /**
29741 * The size in pixels of the latest atlas image.
29742 * @private
29743 * @type {number}
29744 */
29745 this.currentSize_ = options.initialSize !== undefined ?
29746 options.initialSize : ol.INITIAL_ATLAS_SIZE;
29747
29748 /**
29749 * The maximum size in pixels of atlas images.
29750 * @private
29751 * @type {number}
29752 */
29753 this.maxSize_ = options.maxSize !== undefined ?
29754 options.maxSize : ol.MAX_ATLAS_SIZE != -1 ?
29755 ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ?
29756 ol.WEBGL_MAX_TEXTURE_SIZE : 2048;
29757
29758 /**
29759 * The size in pixels between images.
29760 * @private
29761 * @type {number}
29762 */
29763 this.space_ = options.space !== undefined ? options.space : 1;
29764
29765 /**
29766 * @private
29767 * @type {Array.<ol.style.Atlas>}
29768 */
29769 this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)];
29770
29771 /**
29772 * The size in pixels of the latest atlas image for hit-detection images.
29773 * @private
29774 * @type {number}
29775 */
29776 this.currentHitSize_ = this.currentSize_;
29777
29778 /**
29779 * @private
29780 * @type {Array.<ol.style.Atlas>}
29781 */
29782 this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)];
29783};
29784
29785
29786/**
29787 * @param {string} id The identifier of the entry to check.
29788 * @return {?ol.AtlasManagerInfo} The position and atlas image for the
29789 * entry, or `null` if the entry is not part of the atlas manager.
29790 */
29791ol.style.AtlasManager.prototype.getInfo = function(id) {
29792 /** @type {?ol.AtlasInfo} */
29793 var info = this.getInfo_(this.atlases_, id);
29794
29795 if (!info) {
29796 return null;
29797 }
29798 var hitInfo = /** @type {ol.AtlasInfo} */ (this.getInfo_(this.hitAtlases_, id));
29799
29800 return this.mergeInfos_(info, hitInfo);
29801};
29802
29803
29804/**
29805 * @private
29806 * @param {Array.<ol.style.Atlas>} atlases The atlases to search.
29807 * @param {string} id The identifier of the entry to check.
29808 * @return {?ol.AtlasInfo} The position and atlas image for the entry,
29809 * or `null` if the entry is not part of the atlases.
29810 */
29811ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) {
29812 var atlas, info, i, ii;
29813 for (i = 0, ii = atlases.length; i < ii; ++i) {
29814 atlas = atlases[i];
29815 info = atlas.get(id);
29816 if (info) {
29817 return info;
29818 }
29819 }
29820 return null;
29821};
29822
29823
29824/**
29825 * @private
29826 * @param {ol.AtlasInfo} info The info for the real image.
29827 * @param {ol.AtlasInfo} hitInfo The info for the hit-detection
29828 * image.
29829 * @return {?ol.AtlasManagerInfo} The position and atlas image for the
29830 * entry, or `null` if the entry is not part of the atlases.
29831 */
29832ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) {
29833 return /** @type {ol.AtlasManagerInfo} */ ({
29834 offsetX: info.offsetX,
29835 offsetY: info.offsetY,
29836 image: info.image,
29837 hitImage: hitInfo.image
29838 });
29839};
29840
29841
29842/**
29843 * Add an image to the atlas manager.
29844 *
29845 * If an entry for the given id already exists, the entry will
29846 * be overridden (but the space on the atlas graphic will not be freed).
29847 *
29848 * If `renderHitCallback` is provided, the image (or the hit-detection version
29849 * of the image) will be rendered into a separate hit-detection atlas image.
29850 *
29851 * @param {string} id The identifier of the entry to add.
29852 * @param {number} width The width.
29853 * @param {number} height The height.
29854 * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
29855 * Called to render the new image onto an atlas image.
29856 * @param {function(CanvasRenderingContext2D, number, number)=}
29857 * opt_renderHitCallback Called to render a hit-detection image onto a hit
29858 * detection atlas image.
29859 * @param {Object=} opt_this Value to use as `this` when executing
29860 * `renderCallback` and `renderHitCallback`.
29861 * @return {?ol.AtlasManagerInfo} The position and atlas image for the
29862 * entry, or `null` if the image is too big.
29863 */
29864ol.style.AtlasManager.prototype.add = function(id, width, height,
29865 renderCallback, opt_renderHitCallback, opt_this) {
29866 if (width + this.space_ > this.maxSize_ ||
29867 height + this.space_ > this.maxSize_) {
29868 return null;
29869 }
29870
29871 /** @type {?ol.AtlasInfo} */
29872 var info = this.add_(false,
29873 id, width, height, renderCallback, opt_this);
29874 if (!info) {
29875 return null;
29876 }
29877
29878 // even if no hit-detection entry is requested, we insert a fake entry into
29879 // the hit-detection atlas, to make sure that the offset is the same for
29880 // the original image and the hit-detection image.
29881 var renderHitCallback = opt_renderHitCallback !== undefined ?
29882 opt_renderHitCallback : ol.nullFunction;
29883
29884 var hitInfo = /** @type {ol.AtlasInfo} */ (this.add_(true,
29885 id, width, height, renderHitCallback, opt_this));
29886
29887 return this.mergeInfos_(info, hitInfo);
29888};
29889
29890
29891/**
29892 * @private
29893 * @param {boolean} isHitAtlas If the hit-detection atlases are used.
29894 * @param {string} id The identifier of the entry to add.
29895 * @param {number} width The width.
29896 * @param {number} height The height.
29897 * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
29898 * Called to render the new image onto an atlas image.
29899 * @param {Object=} opt_this Value to use as `this` when executing
29900 * `renderCallback` and `renderHitCallback`.
29901 * @return {?ol.AtlasInfo} The position and atlas image for the entry,
29902 * or `null` if the image is too big.
29903 */
29904ol.style.AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height,
29905 renderCallback, opt_this) {
29906 var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_;
29907 var atlas, info, i, ii;
29908 for (i = 0, ii = atlases.length; i < ii; ++i) {
29909 atlas = atlases[i];
29910 info = atlas.add(id, width, height, renderCallback, opt_this);
29911 if (info) {
29912 return info;
29913 } else if (!info && i === ii - 1) {
29914 // the entry could not be added to one of the existing atlases,
29915 // create a new atlas that is twice as big and try to add to this one.
29916 var size;
29917 if (isHitAtlas) {
29918 size = Math.min(this.currentHitSize_ * 2, this.maxSize_);
29919 this.currentHitSize_ = size;
29920 } else {
29921 size = Math.min(this.currentSize_ * 2, this.maxSize_);
29922 this.currentSize_ = size;
29923 }
29924 atlas = new ol.style.Atlas(size, this.space_);
29925 atlases.push(atlas);
29926 // run the loop another time
29927 ++ii;
29928 }
29929 }
29930 return null;
29931};
29932
29933goog.provide('ol.render.webgl.TextReplay');
29934
29935goog.require('ol');
29936goog.require('ol.colorlike');
29937goog.require('ol.dom');
29938goog.require('ol.has');
29939goog.require('ol.render.webgl');
29940goog.require('ol.render.webgl.TextureReplay');
29941goog.require('ol.style.AtlasManager');
29942goog.require('ol.webgl.Buffer');
29943
29944
29945if (ol.ENABLE_WEBGL) {
29946
29947 /**
29948 * @constructor
29949 * @extends {ol.render.webgl.TextureReplay}
29950 * @param {number} tolerance Tolerance.
29951 * @param {ol.Extent} maxExtent Max extent.
29952 * @struct
29953 */
29954 ol.render.webgl.TextReplay = function(tolerance, maxExtent) {
29955 ol.render.webgl.TextureReplay.call(this, tolerance, maxExtent);
29956
29957 /**
29958 * @private
29959 * @type {Array.<HTMLCanvasElement>}
29960 */
29961 this.images_ = [];
29962
29963 /**
29964 * @private
29965 * @type {Array.<WebGLTexture>}
29966 */
29967 this.textures_ = [];
29968
29969 /**
29970 * @private
29971 * @type {HTMLCanvasElement}
29972 */
29973 this.measureCanvas_ = ol.dom.createCanvasContext2D(0, 0).canvas;
29974
29975 /**
29976 * @private
29977 * @type {{strokeColor: (ol.ColorLike|null),
29978 * lineCap: (string|undefined),
29979 * lineDash: Array.<number>,
29980 * lineDashOffset: (number|undefined),
29981 * lineJoin: (string|undefined),
29982 * lineWidth: number,
29983 * miterLimit: (number|undefined),
29984 * fillColor: (ol.ColorLike|null),
29985 * font: (string|undefined),
29986 * scale: (number|undefined)}}
29987 */
29988 this.state_ = {
29989 strokeColor: null,
29990 lineCap: undefined,
29991 lineDash: null,
29992 lineDashOffset: undefined,
29993 lineJoin: undefined,
29994 lineWidth: 0,
29995 miterLimit: undefined,
29996 fillColor: null,
29997 font: undefined,
29998 scale: undefined
29999 };
30000
30001 /**
30002 * @private
30003 * @type {string}
30004 */
30005 this.text_ = '';
30006
30007 /**
30008 * @private
30009 * @type {number|undefined}
30010 */
30011 this.textAlign_ = undefined;
30012
30013 /**
30014 * @private
30015 * @type {number|undefined}
30016 */
30017 this.textBaseline_ = undefined;
30018
30019 /**
30020 * @private
30021 * @type {number|undefined}
30022 */
30023 this.offsetX_ = undefined;
30024
30025 /**
30026 * @private
30027 * @type {number|undefined}
30028 */
30029 this.offsetY_ = undefined;
30030
30031 /**
30032 * @private
30033 * @type {Object.<string, ol.WebglGlyphAtlas>}
30034 */
30035 this.atlases_ = {};
30036
30037 /**
30038 * @private
30039 * @type {ol.WebglGlyphAtlas|undefined}
30040 */
30041 this.currAtlas_ = undefined;
30042
30043 this.scale = 1;
30044
30045 this.opacity = 1;
30046
30047 };
30048 ol.inherits(ol.render.webgl.TextReplay, ol.render.webgl.TextureReplay);
30049
30050
30051 /**
30052 * @inheritDoc
30053 */
30054 ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
30055 end, stride, geometry, feature) {
30056 if (this.text_) {
30057 this.startIndices.push(this.indices.length);
30058 this.startIndicesFeature.push(feature);
30059
30060 var glyphAtlas = this.currAtlas_;
30061 var lines = this.text_.split('\n');
30062 var textSize = this.getTextSize_(lines);
30063 var i, ii, j, jj, currX, currY, charArr, charInfo;
30064 var anchorX = Math.round(textSize[0] * this.textAlign_ - this.offsetX_);
30065 var anchorY = Math.round(textSize[1] * this.textBaseline_ - this.offsetY_);
30066 var lineWidth = (this.state_.lineWidth / 2) * this.state_.scale;
30067
30068 for (i = 0, ii = lines.length; i < ii; ++i) {
30069 currX = 0;
30070 currY = glyphAtlas.height * i;
30071 charArr = lines[i].split('');
30072
30073 for (j = 0, jj = charArr.length; j < jj; ++j) {
30074 charInfo = glyphAtlas.atlas.getInfo(charArr[j]);
30075
30076 if (charInfo) {
30077 var image = charInfo.image;
30078
30079 this.anchorX = anchorX - currX;
30080 this.anchorY = anchorY - currY;
30081 this.originX = j === 0 ? charInfo.offsetX - lineWidth : charInfo.offsetX;
30082 this.originY = charInfo.offsetY;
30083 this.height = glyphAtlas.height;
30084 this.width = j === 0 || j === charArr.length - 1 ?
30085 glyphAtlas.width[charArr[j]] + lineWidth : glyphAtlas.width[charArr[j]];
30086 this.imageHeight = image.height;
30087 this.imageWidth = image.width;
30088
30089 var currentImage;
30090 if (this.images_.length === 0) {
30091 this.images_.push(image);
30092 } else {
30093 currentImage = this.images_[this.images_.length - 1];
30094 if (ol.getUid(currentImage) != ol.getUid(image)) {
30095 this.groupIndices.push(this.indices.length);
30096 this.images_.push(image);
30097 }
30098 }
30099
30100 this.drawText_(flatCoordinates, offset, end, stride);
30101 }
30102 currX += this.width;
30103 }
30104 }
30105 }
30106 };
30107
30108
30109 /**
30110 * @private
30111 * @param {Array.<string>} lines Label to draw split to lines.
30112 * @return {Array.<number>} Size of the label in pixels.
30113 */
30114 ol.render.webgl.TextReplay.prototype.getTextSize_ = function(lines) {
30115 var self = this;
30116 var glyphAtlas = this.currAtlas_;
30117 var textHeight = lines.length * glyphAtlas.height;
30118 //Split every line to an array of chars, sum up their width, and select the longest.
30119 var textWidth = lines.map(function(str) {
30120 var sum = 0;
30121 var i, ii;
30122 for (i = 0, ii = str.length; i < ii; ++i) {
30123 var curr = str[i];
30124 if (!glyphAtlas.width[curr]) {
30125 self.addCharToAtlas_(curr);
30126 }
30127 sum += glyphAtlas.width[curr] ? glyphAtlas.width[curr] : 0;
30128 }
30129 return sum;
30130 }).reduce(function(max, curr) {
30131 return Math.max(max, curr);
30132 });
30133
30134 return [textWidth, textHeight];
30135 };
30136
30137
30138 /**
30139 * @private
30140 * @param {Array.<number>} flatCoordinates Flat coordinates.
30141 * @param {number} offset Offset.
30142 * @param {number} end End.
30143 * @param {number} stride Stride.
30144 */
30145 ol.render.webgl.TextReplay.prototype.drawText_ = function(flatCoordinates, offset,
30146 end, stride) {
30147 var i, ii;
30148 for (i = offset, ii = end; i < ii; i += stride) {
30149 this.drawCoordinates(flatCoordinates, offset, end, stride);
30150 }
30151 };
30152
30153
30154 /**
30155 * @private
30156 * @param {string} char Character.
30157 */
30158 ol.render.webgl.TextReplay.prototype.addCharToAtlas_ = function(char) {
30159 if (char.length === 1) {
30160 var glyphAtlas = this.currAtlas_;
30161 var state = this.state_;
30162 var mCtx = this.measureCanvas_.getContext('2d');
30163 mCtx.font = state.font;
30164 var width = Math.ceil(mCtx.measureText(char).width * state.scale);
30165
30166 var info = glyphAtlas.atlas.add(char, width, glyphAtlas.height,
30167 function(ctx, x, y) {
30168 //Parameterize the canvas
30169 ctx.font = /** @type {string} */ (state.font);
30170 ctx.fillStyle = state.fillColor;
30171 ctx.strokeStyle = state.strokeColor;
30172 ctx.lineWidth = state.lineWidth;
30173 ctx.lineCap = /*** @type {string} */ (state.lineCap);
30174 ctx.lineJoin = /** @type {string} */ (state.lineJoin);
30175 ctx.miterLimit = /** @type {number} */ (state.miterLimit);
30176 ctx.textAlign = 'left';
30177 ctx.textBaseline = 'top';
30178 if (ol.has.CANVAS_LINE_DASH && state.lineDash) {
30179 //FIXME: use pixelRatio
30180 ctx.setLineDash(state.lineDash);
30181 ctx.lineDashOffset = /** @type {number} */ (state.lineDashOffset);
30182 }
30183 if (state.scale !== 1) {
30184 //FIXME: use pixelRatio
30185 ctx.setTransform(/** @type {number} */ (state.scale), 0, 0,
30186 /** @type {number} */ (state.scale), 0, 0);
30187 }
30188
30189 //Draw the character on the canvas
30190 if (state.strokeColor) {
30191 ctx.strokeText(char, x, y);
30192 }
30193 if (state.fillColor) {
30194 ctx.fillText(char, x, y);
30195 }
30196 });
30197
30198 if (info) {
30199 glyphAtlas.width[char] = width;
30200 }
30201 }
30202 };
30203
30204
30205 /**
30206 * @inheritDoc
30207 */
30208 ol.render.webgl.TextReplay.prototype.finish = function(context) {
30209 var gl = context.getGL();
30210
30211 this.groupIndices.push(this.indices.length);
30212 this.hitDetectionGroupIndices = this.groupIndices;
30213
30214 // create, bind, and populate the vertices buffer
30215 this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
30216
30217 // create, bind, and populate the indices buffer
30218 this.indicesBuffer = new ol.webgl.Buffer(this.indices);
30219
30220 // create textures
30221 /** @type {Object.<string, WebGLTexture>} */
30222 var texturePerImage = {};
30223
30224 this.createTextures(this.textures_, this.images_, texturePerImage, gl);
30225
30226 this.state_ = {
30227 strokeColor: null,
30228 lineCap: undefined,
30229 lineDash: null,
30230 lineDashOffset: undefined,
30231 lineJoin: undefined,
30232 lineWidth: 0,
30233 miterLimit: undefined,
30234 fillColor: null,
30235 font: undefined,
30236 scale: undefined
30237 };
30238 this.text_ = '';
30239 this.textAlign_ = undefined;
30240 this.textBaseline_ = undefined;
30241 this.offsetX_ = undefined;
30242 this.offsetY_ = undefined;
30243 this.images_ = null;
30244 this.atlases_ = {};
30245 this.currAtlas_ = undefined;
30246 ol.render.webgl.TextureReplay.prototype.finish.call(this, context);
30247 };
30248
30249
30250 /**
30251 * @inheritDoc
30252 */
30253 ol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {
30254 var state = this.state_;
30255 var textFillStyle = textStyle.getFill();
30256 var textStrokeStyle = textStyle.getStroke();
30257 if (!textStyle || !textStyle.getText() || (!textFillStyle && !textStrokeStyle)) {
30258 this.text_ = '';
30259 } else {
30260 if (!textFillStyle) {
30261 state.fillColor = null;
30262 } else {
30263 var textFillStyleColor = textFillStyle.getColor();
30264 state.fillColor = ol.colorlike.asColorLike(textFillStyleColor ?
30265 textFillStyleColor : ol.render.webgl.defaultFillStyle);
30266 }
30267 if (!textStrokeStyle) {
30268 state.strokeColor = null;
30269 state.lineWidth = 0;
30270 } else {
30271 var textStrokeStyleColor = textStrokeStyle.getColor();
30272 state.strokeColor = ol.colorlike.asColorLike(textStrokeStyleColor ?
30273 textStrokeStyleColor : ol.render.webgl.defaultStrokeStyle);
30274 state.lineWidth = textStrokeStyle.getWidth() || ol.render.webgl.defaultLineWidth;
30275 state.lineCap = textStrokeStyle.getLineCap() || ol.render.webgl.defaultLineCap;
30276 state.lineDashOffset = textStrokeStyle.getLineDashOffset() || ol.render.webgl.defaultLineDashOffset;
30277 state.lineJoin = textStrokeStyle.getLineJoin() || ol.render.webgl.defaultLineJoin;
30278 state.miterLimit = textStrokeStyle.getMiterLimit() || ol.render.webgl.defaultMiterLimit;
30279 var lineDash = textStrokeStyle.getLineDash();
30280 state.lineDash = lineDash ? lineDash.slice() : ol.render.webgl.defaultLineDash;
30281 }
30282 state.font = textStyle.getFont() || ol.render.webgl.defaultFont;
30283 state.scale = textStyle.getScale() || 1;
30284 this.text_ = /** @type {string} */ (textStyle.getText());
30285 var textAlign = ol.render.webgl.TextReplay.Align_[textStyle.getTextAlign()];
30286 var textBaseline = ol.render.webgl.TextReplay.Align_[textStyle.getTextBaseline()];
30287 this.textAlign_ = textAlign === undefined ?
30288 ol.render.webgl.defaultTextAlign : textAlign;
30289 this.textBaseline_ = textBaseline === undefined ?
30290 ol.render.webgl.defaultTextBaseline : textBaseline;
30291 this.offsetX_ = textStyle.getOffsetX() || 0;
30292 this.offsetY_ = textStyle.getOffsetY() || 0;
30293 this.rotateWithView = !!textStyle.getRotateWithView();
30294 this.rotation = textStyle.getRotation() || 0;
30295
30296 this.currAtlas_ = this.getAtlas_(state);
30297 }
30298 };
30299
30300
30301 /**
30302 * @private
30303 * @param {Object} state Font attributes.
30304 * @return {ol.WebglGlyphAtlas} Glyph atlas.
30305 */
30306 ol.render.webgl.TextReplay.prototype.getAtlas_ = function(state) {
30307 var params = [];
30308 var i;
30309 for (i in state) {
30310 if (state[i] || state[i] === 0) {
30311 if (Array.isArray(state[i])) {
30312 params = params.concat(state[i]);
30313 } else {
30314 params.push(state[i]);
30315 }
30316 }
30317 }
30318 var hash = this.calculateHash_(params);
30319 if (!this.atlases_[hash]) {
30320 var mCtx = this.measureCanvas_.getContext('2d');
30321 mCtx.font = state.font;
30322 var height = Math.ceil((mCtx.measureText('M').width * 1.5 +
30323 state.lineWidth / 2) * state.scale);
30324
30325 this.atlases_[hash] = {
30326 atlas: new ol.style.AtlasManager({
30327 space: state.lineWidth + 1
30328 }),
30329 width: {},
30330 height: height
30331 };
30332 }
30333 return this.atlases_[hash];
30334 };
30335
30336
30337 /**
30338 * @private
30339 * @param {Array.<string|number>} params Array of parameters.
30340 * @return {string} Hash string.
30341 */
30342 ol.render.webgl.TextReplay.prototype.calculateHash_ = function(params) {
30343 //TODO: Create a more performant, reliable, general hash function.
30344 var i, ii;
30345 var hash = '';
30346 for (i = 0, ii = params.length; i < ii; ++i) {
30347 hash += params[i];
30348 }
30349 return hash;
30350 };
30351
30352
30353 /**
30354 * @inheritDoc
30355 */
30356 ol.render.webgl.TextReplay.prototype.getTextures = function(opt_all) {
30357 return this.textures_;
30358 };
30359
30360
30361 /**
30362 * @inheritDoc
30363 */
30364 ol.render.webgl.TextReplay.prototype.getHitDetectionTextures = function() {
30365 return this.textures_;
30366 };
30367
30368
30369 /**
30370 * @enum {number}
30371 * @private
30372 */
30373 ol.render.webgl.TextReplay.Align_ = {
30374 left: 0,
30375 end: 0,
30376 center: 0.5,
30377 right: 1,
30378 start: 1,
30379 top: 0,
30380 middle: 0.5,
30381 hanging: 0.2,
30382 alphabetic: 0.8,
30383 ideographic: 0.8,
30384 bottom: 1
30385 };
30386
30387}
30388
30389goog.provide('ol.render.webgl.ReplayGroup');
30390
30391goog.require('ol');
30392goog.require('ol.array');
30393goog.require('ol.extent');
30394goog.require('ol.obj');
30395goog.require('ol.render.replay');
30396goog.require('ol.render.ReplayGroup');
30397goog.require('ol.render.webgl.CircleReplay');
30398goog.require('ol.render.webgl.ImageReplay');
30399goog.require('ol.render.webgl.LineStringReplay');
30400goog.require('ol.render.webgl.PolygonReplay');
30401goog.require('ol.render.webgl.TextReplay');
30402
30403
30404if (ol.ENABLE_WEBGL) {
30405
30406 /**
30407 * @constructor
30408 * @extends {ol.render.ReplayGroup}
30409 * @param {number} tolerance Tolerance.
30410 * @param {ol.Extent} maxExtent Max extent.
30411 * @param {number=} opt_renderBuffer Render buffer.
30412 * @struct
30413 */
30414 ol.render.webgl.ReplayGroup = function(tolerance, maxExtent, opt_renderBuffer) {
30415 ol.render.ReplayGroup.call(this);
30416
30417 /**
30418 * @type {ol.Extent}
30419 * @private
30420 */
30421 this.maxExtent_ = maxExtent;
30422
30423 /**
30424 * @type {number}
30425 * @private
30426 */
30427 this.tolerance_ = tolerance;
30428
30429 /**
30430 * @type {number|undefined}
30431 * @private
30432 */
30433 this.renderBuffer_ = opt_renderBuffer;
30434
30435 /**
30436 * @private
30437 * @type {!Object.<string,
30438 * Object.<ol.render.ReplayType, ol.render.webgl.Replay>>}
30439 */
30440 this.replaysByZIndex_ = {};
30441
30442 };
30443 ol.inherits(ol.render.webgl.ReplayGroup, ol.render.ReplayGroup);
30444
30445
30446 /**
30447 * @param {ol.webgl.Context} context WebGL context.
30448 * @return {function()} Delete resources function.
30449 */
30450 ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = function(context) {
30451 var functions = [];
30452 var zKey;
30453 for (zKey in this.replaysByZIndex_) {
30454 var replays = this.replaysByZIndex_[zKey];
30455 var replayKey;
30456 for (replayKey in replays) {
30457 functions.push(
30458 replays[replayKey].getDeleteResourcesFunction(context));
30459 }
30460 }
30461 return function() {
30462 var length = functions.length;
30463 var result;
30464 for (var i = 0; i < length; i++) {
30465 result = functions[i].apply(this, arguments);
30466 }
30467 return result;
30468 };
30469 };
30470
30471
30472 /**
30473 * @param {ol.webgl.Context} context Context.
30474 */
30475 ol.render.webgl.ReplayGroup.prototype.finish = function(context) {
30476 var zKey;
30477 for (zKey in this.replaysByZIndex_) {
30478 var replays = this.replaysByZIndex_[zKey];
30479 var replayKey;
30480 for (replayKey in replays) {
30481 replays[replayKey].finish(context);
30482 }
30483 }
30484 };
30485
30486
30487 /**
30488 * @inheritDoc
30489 */
30490 ol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
30491 var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
30492 var replays = this.replaysByZIndex_[zIndexKey];
30493 if (replays === undefined) {
30494 replays = {};
30495 this.replaysByZIndex_[zIndexKey] = replays;
30496 }
30497 var replay = replays[replayType];
30498 if (replay === undefined) {
30499 /**
30500 * @type {Function}
30501 */
30502 var Constructor = ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
30503 replay = new Constructor(this.tolerance_, this.maxExtent_);
30504 replays[replayType] = replay;
30505 }
30506 return replay;
30507 };
30508
30509
30510 /**
30511 * @inheritDoc
30512 */
30513 ol.render.webgl.ReplayGroup.prototype.isEmpty = function() {
30514 return ol.obj.isEmpty(this.replaysByZIndex_);
30515 };
30516
30517
30518 /**
30519 * @param {ol.webgl.Context} context Context.
30520 * @param {ol.Coordinate} center Center.
30521 * @param {number} resolution Resolution.
30522 * @param {number} rotation Rotation.
30523 * @param {ol.Size} size Size.
30524 * @param {number} pixelRatio Pixel ratio.
30525 * @param {number} opacity Global opacity.
30526 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
30527 * to skip.
30528 */
30529 ol.render.webgl.ReplayGroup.prototype.replay = function(context,
30530 center, resolution, rotation, size, pixelRatio,
30531 opacity, skippedFeaturesHash) {
30532 /** @type {Array.<number>} */
30533 var zs = Object.keys(this.replaysByZIndex_).map(Number);
30534 zs.sort(ol.array.numberSafeCompareFunction);
30535
30536 var i, ii, j, jj, replays, replay;
30537 for (i = 0, ii = zs.length; i < ii; ++i) {
30538 replays = this.replaysByZIndex_[zs[i].toString()];
30539 for (j = 0, jj = ol.render.replay.ORDER.length; j < jj; ++j) {
30540 replay = replays[ol.render.replay.ORDER[j]];
30541 if (replay !== undefined) {
30542 replay.replay(context,
30543 center, resolution, rotation, size, pixelRatio,
30544 opacity, skippedFeaturesHash,
30545 undefined, false);
30546 }
30547 }
30548 }
30549 };
30550
30551
30552 /**
30553 * @private
30554 * @param {ol.webgl.Context} context Context.
30555 * @param {ol.Coordinate} center Center.
30556 * @param {number} resolution Resolution.
30557 * @param {number} rotation Rotation.
30558 * @param {ol.Size} size Size.
30559 * @param {number} pixelRatio Pixel ratio.
30560 * @param {number} opacity Global opacity.
30561 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
30562 * to skip.
30563 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
30564 * @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
30565 * @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
30566 * this extent are checked.
30567 * @return {T|undefined} Callback result.
30568 * @template T
30569 */
30570 ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context,
30571 center, resolution, rotation, size, pixelRatio, opacity,
30572 skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {
30573 /** @type {Array.<number>} */
30574 var zs = Object.keys(this.replaysByZIndex_).map(Number);
30575 zs.sort(function(a, b) {
30576 return b - a;
30577 });
30578
30579 var i, ii, j, replays, replay, result;
30580 for (i = 0, ii = zs.length; i < ii; ++i) {
30581 replays = this.replaysByZIndex_[zs[i].toString()];
30582 for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
30583 replay = replays[ol.render.replay.ORDER[j]];
30584 if (replay !== undefined) {
30585 result = replay.replay(context,
30586 center, resolution, rotation, size, pixelRatio, opacity,
30587 skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent);
30588 if (result) {
30589 return result;
30590 }
30591 }
30592 }
30593 }
30594 return undefined;
30595 };
30596
30597
30598 /**
30599 * @param {ol.Coordinate} coordinate Coordinate.
30600 * @param {ol.webgl.Context} context Context.
30601 * @param {ol.Coordinate} center Center.
30602 * @param {number} resolution Resolution.
30603 * @param {number} rotation Rotation.
30604 * @param {ol.Size} size Size.
30605 * @param {number} pixelRatio Pixel ratio.
30606 * @param {number} opacity Global opacity.
30607 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
30608 * to skip.
30609 * @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.
30610 * @return {T|undefined} Callback result.
30611 * @template T
30612 */
30613 ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
30614 coordinate, context, center, resolution, rotation, size, pixelRatio,
30615 opacity, skippedFeaturesHash,
30616 callback) {
30617 var gl = context.getGL();
30618 gl.bindFramebuffer(
30619 gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
30620
30621
30622 /**
30623 * @type {ol.Extent}
30624 */
30625 var hitExtent;
30626 if (this.renderBuffer_ !== undefined) {
30627 // build an extent around the coordinate, so that only features that
30628 // intersect this extent are checked
30629 hitExtent = ol.extent.buffer(
30630 ol.extent.createOrUpdateFromCoordinate(coordinate),
30631 resolution * this.renderBuffer_);
30632 }
30633
30634 return this.replayHitDetection_(context,
30635 coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,
30636 pixelRatio, opacity, skippedFeaturesHash,
30637 /**
30638 * @param {ol.Feature|ol.render.Feature} feature Feature.
30639 * @return {?} Callback result.
30640 */
30641 function(feature) {
30642 var imageData = new Uint8Array(4);
30643 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
30644
30645 if (imageData[3] > 0) {
30646 var result = callback(feature);
30647 if (result) {
30648 return result;
30649 }
30650 }
30651 }, true, hitExtent);
30652 };
30653
30654
30655 /**
30656 * @param {ol.Coordinate} coordinate Coordinate.
30657 * @param {ol.webgl.Context} context Context.
30658 * @param {ol.Coordinate} center Center.
30659 * @param {number} resolution Resolution.
30660 * @param {number} rotation Rotation.
30661 * @param {ol.Size} size Size.
30662 * @param {number} pixelRatio Pixel ratio.
30663 * @param {number} opacity Global opacity.
30664 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
30665 * to skip.
30666 * @return {boolean} Is there a feature at the given coordinate?
30667 */
30668 ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function(
30669 coordinate, context, center, resolution, rotation, size, pixelRatio,
30670 opacity, skippedFeaturesHash) {
30671 var gl = context.getGL();
30672 gl.bindFramebuffer(
30673 gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
30674
30675 var hasFeature = this.replayHitDetection_(context,
30676 coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,
30677 pixelRatio, opacity, skippedFeaturesHash,
30678 /**
30679 * @param {ol.Feature|ol.render.Feature} feature Feature.
30680 * @return {boolean} Is there a feature?
30681 */
30682 function(feature) {
30683 var imageData = new Uint8Array(4);
30684 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
30685 return imageData[3] > 0;
30686 }, false);
30687
30688 return hasFeature !== undefined;
30689 };
30690
30691 /**
30692 * @const
30693 * @private
30694 * @type {Array.<number>}
30695 */
30696 ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_ = [1, 1];
30697
30698 /**
30699 * @const
30700 * @private
30701 * @type {Object.<ol.render.ReplayType,
30702 * function(new: ol.render.webgl.Replay, number,
30703 * ol.Extent)>}
30704 */
30705 ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_ = {
30706 'Circle': ol.render.webgl.CircleReplay,
30707 'Image': ol.render.webgl.ImageReplay,
30708 'LineString': ol.render.webgl.LineStringReplay,
30709 'Polygon': ol.render.webgl.PolygonReplay,
30710 'Text': ol.render.webgl.TextReplay
30711 };
30712
30713}
30714
30715goog.provide('ol.render.webgl.Immediate');
30716
30717goog.require('ol');
30718goog.require('ol.extent');
30719goog.require('ol.geom.GeometryType');
30720goog.require('ol.render.ReplayType');
30721goog.require('ol.render.VectorContext');
30722goog.require('ol.render.webgl.ReplayGroup');
30723
30724
30725if (ol.ENABLE_WEBGL) {
30726
30727 /**
30728 * @constructor
30729 * @extends {ol.render.VectorContext}
30730 * @param {ol.webgl.Context} context Context.
30731 * @param {ol.Coordinate} center Center.
30732 * @param {number} resolution Resolution.
30733 * @param {number} rotation Rotation.
30734 * @param {ol.Size} size Size.
30735 * @param {ol.Extent} extent Extent.
30736 * @param {number} pixelRatio Pixel ratio.
30737 * @struct
30738 */
30739 ol.render.webgl.Immediate = function(context, center, resolution, rotation, size, extent, pixelRatio) {
30740 ol.render.VectorContext.call(this);
30741
30742 /**
30743 * @private
30744 */
30745 this.context_ = context;
30746
30747 /**
30748 * @private
30749 */
30750 this.center_ = center;
30751
30752 /**
30753 * @private
30754 */
30755 this.extent_ = extent;
30756
30757 /**
30758 * @private
30759 */
30760 this.pixelRatio_ = pixelRatio;
30761
30762 /**
30763 * @private
30764 */
30765 this.size_ = size;
30766
30767 /**
30768 * @private
30769 */
30770 this.rotation_ = rotation;
30771
30772 /**
30773 * @private
30774 */
30775 this.resolution_ = resolution;
30776
30777 /**
30778 * @private
30779 * @type {ol.style.Image}
30780 */
30781 this.imageStyle_ = null;
30782
30783 /**
30784 * @private
30785 * @type {ol.style.Fill}
30786 */
30787 this.fillStyle_ = null;
30788
30789 /**
30790 * @private
30791 * @type {ol.style.Stroke}
30792 */
30793 this.strokeStyle_ = null;
30794
30795 /**
30796 * @private
30797 * @type {ol.style.Text}
30798 */
30799 this.textStyle_ = null;
30800
30801 };
30802 ol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext);
30803
30804
30805 /**
30806 * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.
30807 * @param {Array.<number>} flatCoordinates Flat coordinates.
30808 * @param {number} offset Offset.
30809 * @param {number} end End.
30810 * @param {number} stride Stride.
30811 * @private
30812 */
30813 ol.render.webgl.Immediate.prototype.drawText_ = function(replayGroup,
30814 flatCoordinates, offset, end, stride) {
30815 var context = this.context_;
30816 var replay = /** @type {ol.render.webgl.TextReplay} */ (
30817 replayGroup.getReplay(0, ol.render.ReplayType.TEXT));
30818 replay.setTextStyle(this.textStyle_);
30819 replay.drawText(flatCoordinates, offset, end, stride, null, null);
30820 replay.finish(context);
30821 // default colors
30822 var opacity = 1;
30823 var skippedFeatures = {};
30824 var featureCallback;
30825 var oneByOne = false;
30826 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
30827 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
30828 oneByOne);
30829 replay.getDeleteResourcesFunction(context)();
30830 };
30831
30832
30833 /**
30834 * Set the rendering style. Note that since this is an immediate rendering API,
30835 * any `zIndex` on the provided style will be ignored.
30836 *
30837 * @param {ol.style.Style} style The rendering style.
30838 * @override
30839 * @api
30840 */
30841 ol.render.webgl.Immediate.prototype.setStyle = function(style) {
30842 this.setFillStrokeStyle(style.getFill(), style.getStroke());
30843 this.setImageStyle(style.getImage());
30844 this.setTextStyle(style.getText());
30845 };
30846
30847
30848 /**
30849 * Render a geometry into the canvas. Call
30850 * {@link ol.render.webgl.Immediate#setStyle} first to set the rendering style.
30851 *
30852 * @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.
30853 * @override
30854 * @api
30855 */
30856 ol.render.webgl.Immediate.prototype.drawGeometry = function(geometry) {
30857 var type = geometry.getType();
30858 switch (type) {
30859 case ol.geom.GeometryType.POINT:
30860 this.drawPoint(/** @type {ol.geom.Point} */ (geometry), null);
30861 break;
30862 case ol.geom.GeometryType.LINE_STRING:
30863 this.drawLineString(/** @type {ol.geom.LineString} */ (geometry), null);
30864 break;
30865 case ol.geom.GeometryType.POLYGON:
30866 this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry), null);
30867 break;
30868 case ol.geom.GeometryType.MULTI_POINT:
30869 this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry), null);
30870 break;
30871 case ol.geom.GeometryType.MULTI_LINE_STRING:
30872 this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry), null);
30873 break;
30874 case ol.geom.GeometryType.MULTI_POLYGON:
30875 this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry), null);
30876 break;
30877 case ol.geom.GeometryType.GEOMETRY_COLLECTION:
30878 this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry), null);
30879 break;
30880 case ol.geom.GeometryType.CIRCLE:
30881 this.drawCircle(/** @type {ol.geom.Circle} */ (geometry), null);
30882 break;
30883 default:
30884 // pass
30885 }
30886 };
30887
30888
30889 /**
30890 * @inheritDoc
30891 * @api
30892 */
30893 ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) {
30894 var geometry = style.getGeometryFunction()(feature);
30895 if (!geometry ||
30896 !ol.extent.intersects(this.extent_, geometry.getExtent())) {
30897 return;
30898 }
30899 this.setStyle(style);
30900 this.drawGeometry(geometry);
30901 };
30902
30903
30904 /**
30905 * @inheritDoc
30906 */
30907 ol.render.webgl.Immediate.prototype.drawGeometryCollection = function(geometry, data) {
30908 var geometries = geometry.getGeometriesArray();
30909 var i, ii;
30910 for (i = 0, ii = geometries.length; i < ii; ++i) {
30911 this.drawGeometry(geometries[i]);
30912 }
30913 };
30914
30915
30916 /**
30917 * @inheritDoc
30918 */
30919 ol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {
30920 var context = this.context_;
30921 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
30922 var replay = /** @type {ol.render.webgl.ImageReplay} */ (
30923 replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
30924 replay.setImageStyle(this.imageStyle_);
30925 replay.drawPoint(geometry, data);
30926 replay.finish(context);
30927 // default colors
30928 var opacity = 1;
30929 var skippedFeatures = {};
30930 var featureCallback;
30931 var oneByOne = false;
30932 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
30933 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
30934 oneByOne);
30935 replay.getDeleteResourcesFunction(context)();
30936
30937 if (this.textStyle_) {
30938 var flatCoordinates = geometry.getFlatCoordinates();
30939 var stride = geometry.getStride();
30940 this.drawText_(replayGroup, flatCoordinates, 0, flatCoordinates.length, stride);
30941 }
30942 };
30943
30944
30945 /**
30946 * @inheritDoc
30947 */
30948 ol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {
30949 var context = this.context_;
30950 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
30951 var replay = /** @type {ol.render.webgl.ImageReplay} */ (
30952 replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
30953 replay.setImageStyle(this.imageStyle_);
30954 replay.drawMultiPoint(geometry, data);
30955 replay.finish(context);
30956 var opacity = 1;
30957 var skippedFeatures = {};
30958 var featureCallback;
30959 var oneByOne = false;
30960 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
30961 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
30962 oneByOne);
30963 replay.getDeleteResourcesFunction(context)();
30964
30965 if (this.textStyle_) {
30966 var flatCoordinates = geometry.getFlatCoordinates();
30967 var stride = geometry.getStride();
30968 this.drawText_(replayGroup, flatCoordinates, 0, flatCoordinates.length, stride);
30969 }
30970 };
30971
30972
30973 /**
30974 * @inheritDoc
30975 */
30976 ol.render.webgl.Immediate.prototype.drawLineString = function(geometry, data) {
30977 var context = this.context_;
30978 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
30979 var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
30980 replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
30981 replay.setFillStrokeStyle(null, this.strokeStyle_);
30982 replay.drawLineString(geometry, data);
30983 replay.finish(context);
30984 var opacity = 1;
30985 var skippedFeatures = {};
30986 var featureCallback;
30987 var oneByOne = false;
30988 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
30989 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
30990 oneByOne);
30991 replay.getDeleteResourcesFunction(context)();
30992
30993 if (this.textStyle_) {
30994 var flatMidpoint = geometry.getFlatMidpoint();
30995 this.drawText_(replayGroup, flatMidpoint, 0, 2, 2);
30996 }
30997 };
30998
30999
31000 /**
31001 * @inheritDoc
31002 */
31003 ol.render.webgl.Immediate.prototype.drawMultiLineString = function(geometry, data) {
31004 var context = this.context_;
31005 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
31006 var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
31007 replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
31008 replay.setFillStrokeStyle(null, this.strokeStyle_);
31009 replay.drawMultiLineString(geometry, data);
31010 replay.finish(context);
31011 var opacity = 1;
31012 var skippedFeatures = {};
31013 var featureCallback;
31014 var oneByOne = false;
31015 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
31016 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
31017 oneByOne);
31018 replay.getDeleteResourcesFunction(context)();
31019
31020 if (this.textStyle_) {
31021 var flatMidpoints = geometry.getFlatMidpoints();
31022 this.drawText_(replayGroup, flatMidpoints, 0, flatMidpoints.length, 2);
31023 }
31024 };
31025
31026
31027 /**
31028 * @inheritDoc
31029 */
31030 ol.render.webgl.Immediate.prototype.drawPolygon = function(geometry, data) {
31031 var context = this.context_;
31032 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
31033 var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
31034 replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
31035 replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
31036 replay.drawPolygon(geometry, data);
31037 replay.finish(context);
31038 var opacity = 1;
31039 var skippedFeatures = {};
31040 var featureCallback;
31041 var oneByOne = false;
31042 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
31043 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
31044 oneByOne);
31045 replay.getDeleteResourcesFunction(context)();
31046
31047 if (this.textStyle_) {
31048 var flatInteriorPoint = geometry.getFlatInteriorPoint();
31049 this.drawText_(replayGroup, flatInteriorPoint, 0, 2, 2);
31050 }
31051 };
31052
31053
31054 /**
31055 * @inheritDoc
31056 */
31057 ol.render.webgl.Immediate.prototype.drawMultiPolygon = function(geometry, data) {
31058 var context = this.context_;
31059 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
31060 var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
31061 replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
31062 replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
31063 replay.drawMultiPolygon(geometry, data);
31064 replay.finish(context);
31065 var opacity = 1;
31066 var skippedFeatures = {};
31067 var featureCallback;
31068 var oneByOne = false;
31069 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
31070 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
31071 oneByOne);
31072 replay.getDeleteResourcesFunction(context)();
31073
31074 if (this.textStyle_) {
31075 var flatInteriorPoints = geometry.getFlatInteriorPoints();
31076 this.drawText_(replayGroup, flatInteriorPoints, 0, flatInteriorPoints.length, 2);
31077 }
31078 };
31079
31080
31081 /**
31082 * @inheritDoc
31083 */
31084 ol.render.webgl.Immediate.prototype.drawCircle = function(geometry, data) {
31085 var context = this.context_;
31086 var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
31087 var replay = /** @type {ol.render.webgl.CircleReplay} */ (
31088 replayGroup.getReplay(0, ol.render.ReplayType.CIRCLE));
31089 replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
31090 replay.drawCircle(geometry, data);
31091 replay.finish(context);
31092 var opacity = 1;
31093 var skippedFeatures = {};
31094 var featureCallback;
31095 var oneByOne = false;
31096 replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
31097 this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
31098 oneByOne);
31099 replay.getDeleteResourcesFunction(context)();
31100
31101 if (this.textStyle_) {
31102 this.drawText_(replayGroup, geometry.getCenter(), 0, 2, 2);
31103 }
31104 };
31105
31106
31107 /**
31108 * @inheritDoc
31109 */
31110 ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) {
31111 this.imageStyle_ = imageStyle;
31112 };
31113
31114
31115 /**
31116 * @inheritDoc
31117 */
31118 ol.render.webgl.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
31119 this.fillStyle_ = fillStyle;
31120 this.strokeStyle_ = strokeStyle;
31121 };
31122
31123
31124 /**
31125 * @inheritDoc
31126 */
31127 ol.render.webgl.Immediate.prototype.setTextStyle = function(textStyle) {
31128 this.textStyle_ = textStyle;
31129 };
31130
31131}
31132
31133goog.provide('ol.structs.LRUCache');
31134
31135goog.require('ol.asserts');
31136
31137
31138/**
31139 * Implements a Least-Recently-Used cache where the keys do not conflict with
31140 * Object's properties (e.g. 'hasOwnProperty' is not allowed as a key). Expiring
31141 * items from the cache is the responsibility of the user.
31142 * @constructor
31143 * @struct
31144 * @template T
31145 */
31146ol.structs.LRUCache = function() {
31147
31148 /**
31149 * @private
31150 * @type {number}
31151 */
31152 this.count_ = 0;
31153
31154 /**
31155 * @private
31156 * @type {!Object.<string, ol.LRUCacheEntry>}
31157 */
31158 this.entries_ = {};
31159
31160 /**
31161 * @private
31162 * @type {?ol.LRUCacheEntry}
31163 */
31164 this.oldest_ = null;
31165
31166 /**
31167 * @private
31168 * @type {?ol.LRUCacheEntry}
31169 */
31170 this.newest_ = null;
31171
31172};
31173
31174
31175/**
31176 * FIXME empty description for jsdoc
31177 */
31178ol.structs.LRUCache.prototype.clear = function() {
31179 this.count_ = 0;
31180 this.entries_ = {};
31181 this.oldest_ = null;
31182 this.newest_ = null;
31183};
31184
31185
31186/**
31187 * @param {string} key Key.
31188 * @return {boolean} Contains key.
31189 */
31190ol.structs.LRUCache.prototype.containsKey = function(key) {
31191 return this.entries_.hasOwnProperty(key);
31192};
31193
31194
31195/**
31196 * @param {function(this: S, T, string, ol.structs.LRUCache): ?} f The function
31197 * to call for every entry from the oldest to the newer. This function takes
31198 * 3 arguments (the entry value, the entry key and the LRUCache object).
31199 * The return value is ignored.
31200 * @param {S=} opt_this The object to use as `this` in `f`.
31201 * @template S
31202 */
31203ol.structs.LRUCache.prototype.forEach = function(f, opt_this) {
31204 var entry = this.oldest_;
31205 while (entry) {
31206 f.call(opt_this, entry.value_, entry.key_, this);
31207 entry = entry.newer;
31208 }
31209};
31210
31211
31212/**
31213 * @param {string} key Key.
31214 * @return {T} Value.
31215 */
31216ol.structs.LRUCache.prototype.get = function(key) {
31217 var entry = this.entries_[key];
31218 ol.asserts.assert(entry !== undefined,
31219 15); // Tried to get a value for a key that does not exist in the cache
31220 if (entry === this.newest_) {
31221 return entry.value_;
31222 } else if (entry === this.oldest_) {
31223 this.oldest_ = /** @type {ol.LRUCacheEntry} */ (this.oldest_.newer);
31224 this.oldest_.older = null;
31225 } else {
31226 entry.newer.older = entry.older;
31227 entry.older.newer = entry.newer;
31228 }
31229 entry.newer = null;
31230 entry.older = this.newest_;
31231 this.newest_.newer = entry;
31232 this.newest_ = entry;
31233 return entry.value_;
31234};
31235
31236
31237/**
31238 * @return {number} Count.
31239 */
31240ol.structs.LRUCache.prototype.getCount = function() {
31241 return this.count_;
31242};
31243
31244
31245/**
31246 * @return {Array.<string>} Keys.
31247 */
31248ol.structs.LRUCache.prototype.getKeys = function() {
31249 var keys = new Array(this.count_);
31250 var i = 0;
31251 var entry;
31252 for (entry = this.newest_; entry; entry = entry.older) {
31253 keys[i++] = entry.key_;
31254 }
31255 return keys;
31256};
31257
31258
31259/**
31260 * @return {Array.<T>} Values.
31261 */
31262ol.structs.LRUCache.prototype.getValues = function() {
31263 var values = new Array(this.count_);
31264 var i = 0;
31265 var entry;
31266 for (entry = this.newest_; entry; entry = entry.older) {
31267 values[i++] = entry.value_;
31268 }
31269 return values;
31270};
31271
31272
31273/**
31274 * @return {T} Last value.
31275 */
31276ol.structs.LRUCache.prototype.peekLast = function() {
31277 return this.oldest_.value_;
31278};
31279
31280
31281/**
31282 * @return {string} Last key.
31283 */
31284ol.structs.LRUCache.prototype.peekLastKey = function() {
31285 return this.oldest_.key_;
31286};
31287
31288
31289/**
31290 * @return {T} value Value.
31291 */
31292ol.structs.LRUCache.prototype.pop = function() {
31293 var entry = this.oldest_;
31294 delete this.entries_[entry.key_];
31295 if (entry.newer) {
31296 entry.newer.older = null;
31297 }
31298 this.oldest_ = /** @type {ol.LRUCacheEntry} */ (entry.newer);
31299 if (!this.oldest_) {
31300 this.newest_ = null;
31301 }
31302 --this.count_;
31303 return entry.value_;
31304};
31305
31306
31307/**
31308 * @param {string} key Key.
31309 * @param {T} value Value.
31310 */
31311ol.structs.LRUCache.prototype.replace = function(key, value) {
31312 this.get(key); // update `newest_`
31313 this.entries_[key].value_ = value;
31314};
31315
31316
31317/**
31318 * @param {string} key Key.
31319 * @param {T} value Value.
31320 */
31321ol.structs.LRUCache.prototype.set = function(key, value) {
31322 ol.asserts.assert(!(key in this.entries_),
31323 16); // Tried to set a value for a key that is used already
31324 var entry = /** @type {ol.LRUCacheEntry} */ ({
31325 key_: key,
31326 newer: null,
31327 older: this.newest_,
31328 value_: value
31329 });
31330 if (!this.newest_) {
31331 this.oldest_ = entry;
31332 } else {
31333 this.newest_.newer = entry;
31334 }
31335 this.newest_ = entry;
31336 this.entries_[key] = entry;
31337 ++this.count_;
31338};
31339
31340// FIXME check against gl.getParameter(webgl.MAX_TEXTURE_SIZE)
31341
31342goog.provide('ol.renderer.webgl.Map');
31343
31344goog.require('ol');
31345goog.require('ol.array');
31346goog.require('ol.css');
31347goog.require('ol.dom');
31348goog.require('ol.events');
31349goog.require('ol.layer.Layer');
31350goog.require('ol.render.Event');
31351goog.require('ol.render.EventType');
31352goog.require('ol.render.webgl.Immediate');
31353goog.require('ol.renderer.Map');
31354goog.require('ol.renderer.Type');
31355goog.require('ol.source.State');
31356goog.require('ol.structs.LRUCache');
31357goog.require('ol.structs.PriorityQueue');
31358goog.require('ol.webgl');
31359goog.require('ol.webgl.Context');
31360goog.require('ol.webgl.ContextEventType');
31361
31362
31363if (ol.ENABLE_WEBGL) {
31364
31365 /**
31366 * @constructor
31367 * @extends {ol.renderer.Map}
31368 * @param {Element} container Container.
31369 * @param {ol.Map} map Map.
31370 */
31371 ol.renderer.webgl.Map = function(container, map) {
31372 ol.renderer.Map.call(this, container, map);
31373
31374 /**
31375 * @private
31376 * @type {HTMLCanvasElement}
31377 */
31378 this.canvas_ = /** @type {HTMLCanvasElement} */
31379 (document.createElement('CANVAS'));
31380 this.canvas_.style.width = '100%';
31381 this.canvas_.style.height = '100%';
31382 this.canvas_.style.display = 'block';
31383 this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
31384 container.insertBefore(this.canvas_, container.childNodes[0] || null);
31385
31386 /**
31387 * @private
31388 * @type {number}
31389 */
31390 this.clipTileCanvasWidth_ = 0;
31391
31392 /**
31393 * @private
31394 * @type {number}
31395 */
31396 this.clipTileCanvasHeight_ = 0;
31397
31398 /**
31399 * @private
31400 * @type {CanvasRenderingContext2D}
31401 */
31402 this.clipTileContext_ = ol.dom.createCanvasContext2D();
31403
31404 /**
31405 * @private
31406 * @type {boolean}
31407 */
31408 this.renderedVisible_ = true;
31409
31410 /**
31411 * @private
31412 * @type {WebGLRenderingContext}
31413 */
31414 this.gl_ = ol.webgl.getContext(this.canvas_, {
31415 antialias: true,
31416 depth: true,
31417 failIfMajorPerformanceCaveat: true,
31418 preserveDrawingBuffer: false,
31419 stencil: true
31420 });
31421
31422 /**
31423 * @private
31424 * @type {ol.webgl.Context}
31425 */
31426 this.context_ = new ol.webgl.Context(this.canvas_, this.gl_);
31427
31428 ol.events.listen(this.canvas_, ol.webgl.ContextEventType.LOST,
31429 this.handleWebGLContextLost, this);
31430 ol.events.listen(this.canvas_, ol.webgl.ContextEventType.RESTORED,
31431 this.handleWebGLContextRestored, this);
31432
31433 /**
31434 * @private
31435 * @type {ol.structs.LRUCache.<ol.WebglTextureCacheEntry|null>}
31436 */
31437 this.textureCache_ = new ol.structs.LRUCache();
31438
31439 /**
31440 * @private
31441 * @type {ol.Coordinate}
31442 */
31443 this.focus_ = null;
31444
31445 /**
31446 * @private
31447 * @type {ol.structs.PriorityQueue.<Array>}
31448 */
31449 this.tileTextureQueue_ = new ol.structs.PriorityQueue(
31450 /**
31451 * @param {Array.<*>} element Element.
31452 * @return {number} Priority.
31453 * @this {ol.renderer.webgl.Map}
31454 */
31455 (function(element) {
31456 var tileCenter = /** @type {ol.Coordinate} */ (element[1]);
31457 var tileResolution = /** @type {number} */ (element[2]);
31458 var deltaX = tileCenter[0] - this.focus_[0];
31459 var deltaY = tileCenter[1] - this.focus_[1];
31460 return 65536 * Math.log(tileResolution) +
31461 Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
31462 }).bind(this),
31463 /**
31464 * @param {Array.<*>} element Element.
31465 * @return {string} Key.
31466 */
31467 function(element) {
31468 return /** @type {ol.Tile} */ (element[0]).getKey();
31469 });
31470
31471
31472 /**
31473 * @param {ol.Map} map Map.
31474 * @param {?olx.FrameState} frameState Frame state.
31475 * @return {boolean} false.
31476 * @this {ol.renderer.webgl.Map}
31477 */
31478 this.loadNextTileTexture_ =
31479 function(map, frameState) {
31480 if (!this.tileTextureQueue_.isEmpty()) {
31481 this.tileTextureQueue_.reprioritize();
31482 var element = this.tileTextureQueue_.dequeue();
31483 var tile = /** @type {ol.Tile} */ (element[0]);
31484 var tileSize = /** @type {ol.Size} */ (element[3]);
31485 var tileGutter = /** @type {number} */ (element[4]);
31486 this.bindTileTexture(
31487 tile, tileSize, tileGutter, ol.webgl.LINEAR, ol.webgl.LINEAR);
31488 }
31489 return false;
31490 }.bind(this);
31491
31492
31493 /**
31494 * @private
31495 * @type {number}
31496 */
31497 this.textureCacheFrameMarkerCount_ = 0;
31498
31499 this.initializeGL_();
31500 };
31501 ol.inherits(ol.renderer.webgl.Map, ol.renderer.Map);
31502
31503
31504 /**
31505 * @param {ol.Tile} tile Tile.
31506 * @param {ol.Size} tileSize Tile size.
31507 * @param {number} tileGutter Tile gutter.
31508 * @param {number} magFilter Mag filter.
31509 * @param {number} minFilter Min filter.
31510 */
31511 ol.renderer.webgl.Map.prototype.bindTileTexture = function(tile, tileSize, tileGutter, magFilter, minFilter) {
31512 var gl = this.getGL();
31513 var tileKey = tile.getKey();
31514 if (this.textureCache_.containsKey(tileKey)) {
31515 var textureCacheEntry = this.textureCache_.get(tileKey);
31516 gl.bindTexture(ol.webgl.TEXTURE_2D, textureCacheEntry.texture);
31517 if (textureCacheEntry.magFilter != magFilter) {
31518 gl.texParameteri(
31519 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MAG_FILTER, magFilter);
31520 textureCacheEntry.magFilter = magFilter;
31521 }
31522 if (textureCacheEntry.minFilter != minFilter) {
31523 gl.texParameteri(
31524 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MIN_FILTER, minFilter);
31525 textureCacheEntry.minFilter = minFilter;
31526 }
31527 } else {
31528 var texture = gl.createTexture();
31529 gl.bindTexture(ol.webgl.TEXTURE_2D, texture);
31530 if (tileGutter > 0) {
31531 var clipTileCanvas = this.clipTileContext_.canvas;
31532 var clipTileContext = this.clipTileContext_;
31533 if (this.clipTileCanvasWidth_ !== tileSize[0] ||
31534 this.clipTileCanvasHeight_ !== tileSize[1]) {
31535 clipTileCanvas.width = tileSize[0];
31536 clipTileCanvas.height = tileSize[1];
31537 this.clipTileCanvasWidth_ = tileSize[0];
31538 this.clipTileCanvasHeight_ = tileSize[1];
31539 } else {
31540 clipTileContext.clearRect(0, 0, tileSize[0], tileSize[1]);
31541 }
31542 clipTileContext.drawImage(tile.getImage(), tileGutter, tileGutter,
31543 tileSize[0], tileSize[1], 0, 0, tileSize[0], tileSize[1]);
31544 gl.texImage2D(ol.webgl.TEXTURE_2D, 0,
31545 ol.webgl.RGBA, ol.webgl.RGBA,
31546 ol.webgl.UNSIGNED_BYTE, clipTileCanvas);
31547 } else {
31548 gl.texImage2D(ol.webgl.TEXTURE_2D, 0,
31549 ol.webgl.RGBA, ol.webgl.RGBA,
31550 ol.webgl.UNSIGNED_BYTE, tile.getImage());
31551 }
31552 gl.texParameteri(
31553 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MAG_FILTER, magFilter);
31554 gl.texParameteri(
31555 ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_MIN_FILTER, minFilter);
31556 gl.texParameteri(ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_S,
31557 ol.webgl.CLAMP_TO_EDGE);
31558 gl.texParameteri(ol.webgl.TEXTURE_2D, ol.webgl.TEXTURE_WRAP_T,
31559 ol.webgl.CLAMP_TO_EDGE);
31560 this.textureCache_.set(tileKey, {
31561 texture: texture,
31562 magFilter: magFilter,
31563 minFilter: minFilter
31564 });
31565 }
31566 };
31567
31568
31569 /**
31570 * @param {ol.render.EventType} type Event type.
31571 * @param {olx.FrameState} frameState Frame state.
31572 * @private
31573 */
31574 ol.renderer.webgl.Map.prototype.dispatchComposeEvent_ = function(type, frameState) {
31575 var map = this.getMap();
31576 if (map.hasListener(type)) {
31577 var context = this.context_;
31578
31579 var extent = frameState.extent;
31580 var size = frameState.size;
31581 var viewState = frameState.viewState;
31582 var pixelRatio = frameState.pixelRatio;
31583
31584 var resolution = viewState.resolution;
31585 var center = viewState.center;
31586 var rotation = viewState.rotation;
31587
31588 var vectorContext = new ol.render.webgl.Immediate(context,
31589 center, resolution, rotation, size, extent, pixelRatio);
31590 var composeEvent = new ol.render.Event(type, vectorContext,
31591 frameState, null, context);
31592 map.dispatchEvent(composeEvent);
31593 }
31594 };
31595
31596
31597 /**
31598 * @inheritDoc
31599 */
31600 ol.renderer.webgl.Map.prototype.disposeInternal = function() {
31601 var gl = this.getGL();
31602 if (!gl.isContextLost()) {
31603 this.textureCache_.forEach(
31604 /**
31605 * @param {?ol.WebglTextureCacheEntry} textureCacheEntry
31606 * Texture cache entry.
31607 */
31608 function(textureCacheEntry) {
31609 if (textureCacheEntry) {
31610 gl.deleteTexture(textureCacheEntry.texture);
31611 }
31612 });
31613 }
31614 this.context_.dispose();
31615 ol.renderer.Map.prototype.disposeInternal.call(this);
31616 };
31617
31618
31619 /**
31620 * @param {ol.Map} map Map.
31621 * @param {olx.FrameState} frameState Frame state.
31622 * @private
31623 */
31624 ol.renderer.webgl.Map.prototype.expireCache_ = function(map, frameState) {
31625 var gl = this.getGL();
31626 var textureCacheEntry;
31627 while (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >
31628 ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {
31629 textureCacheEntry = this.textureCache_.peekLast();
31630 if (!textureCacheEntry) {
31631 if (+this.textureCache_.peekLastKey() == frameState.index) {
31632 break;
31633 } else {
31634 --this.textureCacheFrameMarkerCount_;
31635 }
31636 } else {
31637 gl.deleteTexture(textureCacheEntry.texture);
31638 }
31639 this.textureCache_.pop();
31640 }
31641 };
31642
31643
31644 /**
31645 * @return {ol.webgl.Context} The context.
31646 */
31647 ol.renderer.webgl.Map.prototype.getContext = function() {
31648 return this.context_;
31649 };
31650
31651
31652 /**
31653 * @return {WebGLRenderingContext} GL.
31654 */
31655 ol.renderer.webgl.Map.prototype.getGL = function() {
31656 return this.gl_;
31657 };
31658
31659
31660 /**
31661 * @return {ol.structs.PriorityQueue.<Array>} Tile texture queue.
31662 */
31663 ol.renderer.webgl.Map.prototype.getTileTextureQueue = function() {
31664 return this.tileTextureQueue_;
31665 };
31666
31667
31668 /**
31669 * @inheritDoc
31670 */
31671 ol.renderer.webgl.Map.prototype.getType = function() {
31672 return ol.renderer.Type.WEBGL;
31673 };
31674
31675
31676 /**
31677 * @param {ol.events.Event} event Event.
31678 * @protected
31679 */
31680 ol.renderer.webgl.Map.prototype.handleWebGLContextLost = function(event) {
31681 event.preventDefault();
31682 this.textureCache_.clear();
31683 this.textureCacheFrameMarkerCount_ = 0;
31684
31685 var renderers = this.getLayerRenderers();
31686 for (var id in renderers) {
31687 var renderer = /** @type {ol.renderer.webgl.Layer} */ (renderers[id]);
31688 renderer.handleWebGLContextLost();
31689 }
31690 };
31691
31692
31693 /**
31694 * @protected
31695 */
31696 ol.renderer.webgl.Map.prototype.handleWebGLContextRestored = function() {
31697 this.initializeGL_();
31698 this.getMap().render();
31699 };
31700
31701
31702 /**
31703 * @private
31704 */
31705 ol.renderer.webgl.Map.prototype.initializeGL_ = function() {
31706 var gl = this.gl_;
31707 gl.activeTexture(ol.webgl.TEXTURE0);
31708 gl.blendFuncSeparate(
31709 ol.webgl.SRC_ALPHA, ol.webgl.ONE_MINUS_SRC_ALPHA,
31710 ol.webgl.ONE, ol.webgl.ONE_MINUS_SRC_ALPHA);
31711 gl.disable(ol.webgl.CULL_FACE);
31712 gl.disable(ol.webgl.DEPTH_TEST);
31713 gl.disable(ol.webgl.SCISSOR_TEST);
31714 gl.disable(ol.webgl.STENCIL_TEST);
31715 };
31716
31717
31718 /**
31719 * @param {ol.Tile} tile Tile.
31720 * @return {boolean} Is tile texture loaded.
31721 */
31722 ol.renderer.webgl.Map.prototype.isTileTextureLoaded = function(tile) {
31723 return this.textureCache_.containsKey(tile.getKey());
31724 };
31725
31726
31727 /**
31728 * @inheritDoc
31729 */
31730 ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) {
31731
31732 var context = this.getContext();
31733 var gl = this.getGL();
31734
31735 if (gl.isContextLost()) {
31736 return false;
31737 }
31738
31739 if (!frameState) {
31740 if (this.renderedVisible_) {
31741 this.canvas_.style.display = 'none';
31742 this.renderedVisible_ = false;
31743 }
31744 return false;
31745 }
31746
31747 this.focus_ = frameState.focus;
31748
31749 this.textureCache_.set((-frameState.index).toString(), null);
31750 ++this.textureCacheFrameMarkerCount_;
31751
31752 this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, frameState);
31753
31754 /** @type {Array.<ol.LayerState>} */
31755 var layerStatesToDraw = [];
31756 var layerStatesArray = frameState.layerStatesArray;
31757 ol.array.stableSort(layerStatesArray, ol.renderer.Map.sortByZIndex);
31758
31759 var viewResolution = frameState.viewState.resolution;
31760 var i, ii, layerRenderer, layerState;
31761 for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
31762 layerState = layerStatesArray[i];
31763 if (ol.layer.Layer.visibleAtResolution(layerState, viewResolution) &&
31764 layerState.sourceState == ol.source.State.READY) {
31765 layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layerState.layer));
31766 if (layerRenderer.prepareFrame(frameState, layerState, context)) {
31767 layerStatesToDraw.push(layerState);
31768 }
31769 }
31770 }
31771
31772 var width = frameState.size[0] * frameState.pixelRatio;
31773 var height = frameState.size[1] * frameState.pixelRatio;
31774 if (this.canvas_.width != width || this.canvas_.height != height) {
31775 this.canvas_.width = width;
31776 this.canvas_.height = height;
31777 }
31778
31779 gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, null);
31780
31781 gl.clearColor(0, 0, 0, 0);
31782 gl.clear(ol.webgl.COLOR_BUFFER_BIT);
31783 gl.enable(ol.webgl.BLEND);
31784 gl.viewport(0, 0, this.canvas_.width, this.canvas_.height);
31785
31786 for (i = 0, ii = layerStatesToDraw.length; i < ii; ++i) {
31787 layerState = layerStatesToDraw[i];
31788 layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layerState.layer));
31789 layerRenderer.composeFrame(frameState, layerState, context);
31790 }
31791
31792 if (!this.renderedVisible_) {
31793 this.canvas_.style.display = '';
31794 this.renderedVisible_ = true;
31795 }
31796
31797 this.calculateMatrices2D(frameState);
31798
31799 if (this.textureCache_.getCount() - this.textureCacheFrameMarkerCount_ >
31800 ol.WEBGL_TEXTURE_CACHE_HIGH_WATER_MARK) {
31801 frameState.postRenderFunctions.push(
31802 /** @type {ol.PostRenderFunction} */ (this.expireCache_.bind(this))
31803 );
31804 }
31805
31806 if (!this.tileTextureQueue_.isEmpty()) {
31807 frameState.postRenderFunctions.push(this.loadNextTileTexture_);
31808 frameState.animate = true;
31809 }
31810
31811 this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, frameState);
31812
31813 this.scheduleRemoveUnusedLayerRenderers(frameState);
31814 this.scheduleExpireIconCache(frameState);
31815
31816 };
31817
31818
31819 /**
31820 * @inheritDoc
31821 */
31822 ol.renderer.webgl.Map.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg,
31823 layerFilter, thisArg2) {
31824 var result;
31825
31826 if (this.getGL().isContextLost()) {
31827 return false;
31828 }
31829
31830 var viewState = frameState.viewState;
31831
31832 var layerStates = frameState.layerStatesArray;
31833 var numLayers = layerStates.length;
31834 var i;
31835 for (i = numLayers - 1; i >= 0; --i) {
31836 var layerState = layerStates[i];
31837 var layer = layerState.layer;
31838 if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
31839 layerFilter.call(thisArg2, layer)) {
31840 var layerRenderer = this.getLayerRenderer(layer);
31841 result = layerRenderer.forEachFeatureAtCoordinate(
31842 coordinate, frameState, hitTolerance, callback, thisArg);
31843 if (result) {
31844 return result;
31845 }
31846 }
31847 }
31848 return undefined;
31849 };
31850
31851
31852 /**
31853 * @inheritDoc
31854 */
31855 ol.renderer.webgl.Map.prototype.hasFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, layerFilter, thisArg) {
31856 var hasFeature = false;
31857
31858 if (this.getGL().isContextLost()) {
31859 return false;
31860 }
31861
31862 var viewState = frameState.viewState;
31863
31864 var layerStates = frameState.layerStatesArray;
31865 var numLayers = layerStates.length;
31866 var i;
31867 for (i = numLayers - 1; i >= 0; --i) {
31868 var layerState = layerStates[i];
31869 var layer = layerState.layer;
31870 if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
31871 layerFilter.call(thisArg, layer)) {
31872 var layerRenderer = this.getLayerRenderer(layer);
31873 hasFeature =
31874 layerRenderer.hasFeatureAtCoordinate(coordinate, frameState);
31875 if (hasFeature) {
31876 return true;
31877 }
31878 }
31879 }
31880 return hasFeature;
31881 };
31882
31883
31884 /**
31885 * @inheritDoc
31886 */
31887 ol.renderer.webgl.Map.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg,
31888 layerFilter, thisArg2) {
31889 if (this.getGL().isContextLost()) {
31890 return false;
31891 }
31892
31893 var viewState = frameState.viewState;
31894 var result;
31895
31896 var layerStates = frameState.layerStatesArray;
31897 var numLayers = layerStates.length;
31898 var i;
31899 for (i = numLayers - 1; i >= 0; --i) {
31900 var layerState = layerStates[i];
31901 var layer = layerState.layer;
31902 if (ol.layer.Layer.visibleAtResolution(layerState, viewState.resolution) &&
31903 layerFilter.call(thisArg, layer)) {
31904 var layerRenderer = /** @type {ol.renderer.webgl.Layer} */ (this.getLayerRenderer(layer));
31905 result = layerRenderer.forEachLayerAtPixel(
31906 pixel, frameState, callback, thisArg);
31907 if (result) {
31908 return result;
31909 }
31910 }
31911 }
31912 return undefined;
31913 };
31914
31915}
31916
31917// FIXME recheck layer/map projection compatibility when projection changes
31918// FIXME layer renderers should skip when they can't reproject
31919// FIXME add tilt and height?
31920
31921goog.provide('ol.Map');
31922
31923goog.require('ol');
31924goog.require('ol.Collection');
31925goog.require('ol.CollectionEventType');
31926goog.require('ol.MapBrowserEvent');
31927goog.require('ol.MapBrowserEventHandler');
31928goog.require('ol.MapBrowserEventType');
31929goog.require('ol.MapEvent');
31930goog.require('ol.MapEventType');
31931goog.require('ol.MapProperty');
31932goog.require('ol.Object');
31933goog.require('ol.ObjectEventType');
31934goog.require('ol.TileQueue');
31935goog.require('ol.View');
31936goog.require('ol.ViewHint');
31937goog.require('ol.asserts');
31938goog.require('ol.control');
31939goog.require('ol.dom');
31940goog.require('ol.events');
31941goog.require('ol.events.Event');
31942goog.require('ol.events.EventType');
31943goog.require('ol.extent');
31944goog.require('ol.functions');
31945goog.require('ol.has');
31946goog.require('ol.interaction');
31947goog.require('ol.layer.Group');
31948goog.require('ol.obj');
31949goog.require('ol.renderer.Map');
31950goog.require('ol.renderer.Type');
31951goog.require('ol.renderer.canvas.Map');
31952goog.require('ol.renderer.webgl.Map');
31953goog.require('ol.size');
31954goog.require('ol.structs.PriorityQueue');
31955goog.require('ol.transform');
31956
31957
31958/**
31959 * @const
31960 * @type {string}
31961 */
31962ol.OL_URL = 'https://openlayers.org/';
31963
31964
31965/**
31966 * @const
31967 * @type {string}
31968 */
31969ol.OL_LOGO_URL = 'data:image/png;base64,' +
31970 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAA3NCSVQICAjb4U/gAAAACXBI' +
31971 'WXMAAAHGAAABxgEXwfpGAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAA' +
31972 'AhNQTFRF////AP//AICAgP//AFVVQECA////K1VVSbbbYL/fJ05idsTYJFtbbcjbJllmZszW' +
31973 'WMTOIFhoHlNiZszTa9DdUcHNHlNlV8XRIVdiasrUHlZjIVZjaMnVH1RlIFRkH1RkH1ZlasvY' +
31974 'asvXVsPQH1VkacnVa8vWIVZjIFRjVMPQa8rXIVVkXsXRsNveIFVkIFZlIVVj3eDeh6GmbMvX' +
31975 'H1ZkIFRka8rWbMvXIFVkIFVjIFVkbMvWH1VjbMvWIFVlbcvWIFVla8vVIFVkbMvWbMvVH1Vk' +
31976 'bMvWIFVlbcvWIFVkbcvVbMvWjNPbIFVkU8LPwMzNIFVkbczWIFVkbsvWbMvXIFVkRnB8bcvW' +
31977 '2+TkW8XRIFVkIlZlJVloJlpoKlxrLl9tMmJwOWd0Omh1RXF8TneCT3iDUHiDU8LPVMLPVcLP' +
31978 'VcPQVsPPVsPQV8PQWMTQWsTQW8TQXMXSXsXRX4SNX8bSYMfTYcfTYsfTY8jUZcfSZsnUaIqT' +
31979 'acrVasrVa8jTa8rWbI2VbMvWbcvWdJObdcvUdszUd8vVeJaee87Yfc3WgJyjhqGnitDYjaar' +
31980 'ldPZnrK2oNbborW5o9bbo9fbpLa6q9ndrL3ArtndscDDutzfu8fJwN7gwt7gxc/QyuHhy+Hi' +
31981 'zeHi0NfX0+Pj19zb1+Tj2uXk29/e3uLg3+Lh3+bl4uXj4ufl4+fl5Ofl5ufl5ujm5+jmySDn' +
31982 'BAAAAFp0Uk5TAAECAgMEBAYHCA0NDg4UGRogIiMmKSssLzU7PkJJT1JTVFliY2hrdHZ3foSF' +
31983 'hYeJjY2QkpugqbG1tre5w8zQ09XY3uXn6+zx8vT09vf4+Pj5+fr6/P39/f3+gz7SsAAAAVVJ' +
31984 'REFUOMtjYKA7EBDnwCPLrObS1BRiLoJLnte6CQy8FLHLCzs2QUG4FjZ5GbcmBDDjxJBXDWxC' +
31985 'Brb8aM4zbkIDzpLYnAcE9VXlJSWlZRU13koIeW57mGx5XjoMZEUqwxWYQaQbSzLSkYGfKFSe' +
31986 '0QMsX5WbjgY0YS4MBplemI4BdGBW+DQ11eZiymfqQuXZIjqwyadPNoSZ4L+0FVM6e+oGI6g8' +
31987 'a9iKNT3o8kVzNkzRg5lgl7p4wyRUL9Yt2jAxVh6mQCogae6GmflI8p0r13VFWTHBQ0rWPW7a' +
31988 'hgWVcPm+9cuLoyy4kCJDzCm6d8PSFoh0zvQNC5OjDJhQopPPJqph1doJBUD5tnkbZiUEqaCn' +
31989 'B3bTqLTFG1bPn71kw4b+GFdpLElKIzRxxgYgWNYc5SCENVHKeUaltHdXx0dZ8uBI1hJ2UUDg' +
31990 'q82CM2MwKeibqAvSO7MCABq0wXEPiqWEAAAAAElFTkSuQmCC';
31991
31992
31993/**
31994 * @type {Array.<ol.renderer.Type>}
31995 * @const
31996 */
31997ol.DEFAULT_RENDERER_TYPES = [
31998 ol.renderer.Type.CANVAS,
31999 ol.renderer.Type.WEBGL
32000];
32001
32002
32003/**
32004 * @classdesc
32005 * The map is the core component of OpenLayers. For a map to render, a view,
32006 * one or more layers, and a target container are needed:
32007 *
32008 * var map = new ol.Map({
32009 * view: new ol.View({
32010 * center: [0, 0],
32011 * zoom: 1
32012 * }),
32013 * layers: [
32014 * new ol.layer.Tile({
32015 * source: new ol.source.OSM()
32016 * })
32017 * ],
32018 * target: 'map'
32019 * });
32020 *
32021 * The above snippet creates a map using a {@link ol.layer.Tile} to display
32022 * {@link ol.source.OSM} OSM data and render it to a DOM element with the
32023 * id `map`.
32024 *
32025 * The constructor places a viewport container (with CSS class name
32026 * `ol-viewport`) in the target element (see `getViewport()`), and then two
32027 * further elements within the viewport: one with CSS class name
32028 * `ol-overlaycontainer-stopevent` for controls and some overlays, and one with
32029 * CSS class name `ol-overlaycontainer` for other overlays (see the `stopEvent`
32030 * option of {@link ol.Overlay} for the difference). The map itself is placed in
32031 * a further element within the viewport.
32032 *
32033 * Layers are stored as a `ol.Collection` in layerGroups. A top-level group is
32034 * provided by the library. This is what is accessed by `getLayerGroup` and
32035 * `setLayerGroup`. Layers entered in the options are added to this group, and
32036 * `addLayer` and `removeLayer` change the layer collection in the group.
32037 * `getLayers` is a convenience function for `getLayerGroup().getLayers()`.
32038 * Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers
32039 * entered in the options or added with `addLayer` can be groups, which can
32040 * contain further groups, and so on.
32041 *
32042 * @constructor
32043 * @extends {ol.Object}
32044 * @param {olx.MapOptions} options Map options.
32045 * @fires ol.MapBrowserEvent
32046 * @fires ol.MapEvent
32047 * @fires ol.render.Event#postcompose
32048 * @fires ol.render.Event#precompose
32049 * @api
32050 */
32051ol.Map = function(options) {
32052
32053 ol.Object.call(this);
32054
32055 var optionsInternal = ol.Map.createOptionsInternal(options);
32056
32057 /**
32058 * @type {boolean}
32059 * @private
32060 */
32061 this.loadTilesWhileAnimating_ =
32062 options.loadTilesWhileAnimating !== undefined ?
32063 options.loadTilesWhileAnimating : false;
32064
32065 /**
32066 * @type {boolean}
32067 * @private
32068 */
32069 this.loadTilesWhileInteracting_ =
32070 options.loadTilesWhileInteracting !== undefined ?
32071 options.loadTilesWhileInteracting : false;
32072
32073 /**
32074 * @private
32075 * @type {number}
32076 */
32077 this.pixelRatio_ = options.pixelRatio !== undefined ?
32078 options.pixelRatio : ol.has.DEVICE_PIXEL_RATIO;
32079
32080 /**
32081 * @private
32082 * @type {Object.<string, string>}
32083 */
32084 this.logos_ = optionsInternal.logos;
32085
32086 /**
32087 * @private
32088 * @type {number|undefined}
32089 */
32090 this.animationDelayKey_;
32091
32092 /**
32093 * @private
32094 */
32095 this.animationDelay_ = function() {
32096 this.animationDelayKey_ = undefined;
32097 this.renderFrame_.call(this, Date.now());
32098 }.bind(this);
32099
32100 /**
32101 * @private
32102 * @type {ol.Transform}
32103 */
32104 this.coordinateToPixelTransform_ = ol.transform.create();
32105
32106 /**
32107 * @private
32108 * @type {ol.Transform}
32109 */
32110 this.pixelToCoordinateTransform_ = ol.transform.create();
32111
32112 /**
32113 * @private
32114 * @type {number}
32115 */
32116 this.frameIndex_ = 0;
32117
32118 /**
32119 * @private
32120 * @type {?olx.FrameState}
32121 */
32122 this.frameState_ = null;
32123
32124 /**
32125 * The extent at the previous 'moveend' event.
32126 * @private
32127 * @type {ol.Extent}
32128 */
32129 this.previousExtent_ = null;
32130
32131 /**
32132 * @private
32133 * @type {?ol.EventsKey}
32134 */
32135 this.viewPropertyListenerKey_ = null;
32136
32137 /**
32138 * @private
32139 * @type {?ol.EventsKey}
32140 */
32141 this.viewChangeListenerKey_ = null;
32142
32143 /**
32144 * @private
32145 * @type {Array.<ol.EventsKey>}
32146 */
32147 this.layerGroupPropertyListenerKeys_ = null;
32148
32149 /**
32150 * @private
32151 * @type {Element}
32152 */
32153 this.viewport_ = document.createElement('DIV');
32154 this.viewport_.className = 'ol-viewport' + (ol.has.TOUCH ? ' ol-touch' : '');
32155 this.viewport_.style.position = 'relative';
32156 this.viewport_.style.overflow = 'hidden';
32157 this.viewport_.style.width = '100%';
32158 this.viewport_.style.height = '100%';
32159 // prevent page zoom on IE >= 10 browsers
32160 this.viewport_.style.msTouchAction = 'none';
32161 this.viewport_.style.touchAction = 'none';
32162
32163 /**
32164 * @private
32165 * @type {!Element}
32166 */
32167 this.overlayContainer_ = document.createElement('DIV');
32168 this.overlayContainer_.className = 'ol-overlaycontainer';
32169 this.viewport_.appendChild(this.overlayContainer_);
32170
32171 /**
32172 * @private
32173 * @type {!Element}
32174 */
32175 this.overlayContainerStopEvent_ = document.createElement('DIV');
32176 this.overlayContainerStopEvent_.className = 'ol-overlaycontainer-stopevent';
32177 var overlayEvents = [
32178 ol.events.EventType.CLICK,
32179 ol.events.EventType.DBLCLICK,
32180 ol.events.EventType.MOUSEDOWN,
32181 ol.events.EventType.TOUCHSTART,
32182 ol.events.EventType.MSPOINTERDOWN,
32183 ol.MapBrowserEventType.POINTERDOWN,
32184 ol.events.EventType.MOUSEWHEEL,
32185 ol.events.EventType.WHEEL
32186 ];
32187 for (var i = 0, ii = overlayEvents.length; i < ii; ++i) {
32188 ol.events.listen(this.overlayContainerStopEvent_, overlayEvents[i],
32189 ol.events.Event.stopPropagation);
32190 }
32191 this.viewport_.appendChild(this.overlayContainerStopEvent_);
32192
32193 /**
32194 * @private
32195 * @type {ol.MapBrowserEventHandler}
32196 */
32197 this.mapBrowserEventHandler_ = new ol.MapBrowserEventHandler(this, options.moveTolerance);
32198 for (var key in ol.MapBrowserEventType) {
32199 ol.events.listen(this.mapBrowserEventHandler_, ol.MapBrowserEventType[key],
32200 this.handleMapBrowserEvent, this);
32201 }
32202
32203 /**
32204 * @private
32205 * @type {Element|Document}
32206 */
32207 this.keyboardEventTarget_ = optionsInternal.keyboardEventTarget;
32208
32209 /**
32210 * @private
32211 * @type {Array.<ol.EventsKey>}
32212 */
32213 this.keyHandlerKeys_ = null;
32214
32215 ol.events.listen(this.viewport_, ol.events.EventType.WHEEL,
32216 this.handleBrowserEvent, this);
32217 ol.events.listen(this.viewport_, ol.events.EventType.MOUSEWHEEL,
32218 this.handleBrowserEvent, this);
32219
32220 /**
32221 * @type {ol.Collection.<ol.control.Control>}
32222 * @private
32223 */
32224 this.controls_ = optionsInternal.controls;
32225
32226 /**
32227 * @type {ol.Collection.<ol.interaction.Interaction>}
32228 * @private
32229 */
32230 this.interactions_ = optionsInternal.interactions;
32231
32232 /**
32233 * @type {ol.Collection.<ol.Overlay>}
32234 * @private
32235 */
32236 this.overlays_ = optionsInternal.overlays;
32237
32238 /**
32239 * A lookup of overlays by id.
32240 * @private
32241 * @type {Object.<string, ol.Overlay>}
32242 */
32243 this.overlayIdIndex_ = {};
32244
32245 /**
32246 * @type {ol.renderer.Map}
32247 * @private
32248 */
32249 this.renderer_ = new /** @type {Function} */ (optionsInternal.rendererConstructor)(this.viewport_, this);
32250
32251 /**
32252 * @type {function(Event)|undefined}
32253 * @private
32254 */
32255 this.handleResize_;
32256
32257 /**
32258 * @private
32259 * @type {ol.Coordinate}
32260 */
32261 this.focus_ = null;
32262
32263 /**
32264 * @private
32265 * @type {Array.<ol.PostRenderFunction>}
32266 */
32267 this.postRenderFunctions_ = [];
32268
32269 /**
32270 * @private
32271 * @type {ol.TileQueue}
32272 */
32273 this.tileQueue_ = new ol.TileQueue(
32274 this.getTilePriority.bind(this),
32275 this.handleTileChange_.bind(this));
32276
32277 /**
32278 * Uids of features to skip at rendering time.
32279 * @type {Object.<string, boolean>}
32280 * @private
32281 */
32282 this.skippedFeatureUids_ = {};
32283
32284 ol.events.listen(
32285 this, ol.Object.getChangeEventType(ol.MapProperty.LAYERGROUP),
32286 this.handleLayerGroupChanged_, this);
32287 ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.VIEW),
32288 this.handleViewChanged_, this);
32289 ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.SIZE),
32290 this.handleSizeChanged_, this);
32291 ol.events.listen(this, ol.Object.getChangeEventType(ol.MapProperty.TARGET),
32292 this.handleTargetChanged_, this);
32293
32294 // setProperties will trigger the rendering of the map if the map
32295 // is "defined" already.
32296 this.setProperties(optionsInternal.values);
32297
32298 this.controls_.forEach(
32299 /**
32300 * @param {ol.control.Control} control Control.
32301 * @this {ol.Map}
32302 */
32303 function(control) {
32304 control.setMap(this);
32305 }, this);
32306
32307 ol.events.listen(this.controls_, ol.CollectionEventType.ADD,
32308 /**
32309 * @param {ol.Collection.Event} event Collection event.
32310 */
32311 function(event) {
32312 event.element.setMap(this);
32313 }, this);
32314
32315 ol.events.listen(this.controls_, ol.CollectionEventType.REMOVE,
32316 /**
32317 * @param {ol.Collection.Event} event Collection event.
32318 */
32319 function(event) {
32320 event.element.setMap(null);
32321 }, this);
32322
32323 this.interactions_.forEach(
32324 /**
32325 * @param {ol.interaction.Interaction} interaction Interaction.
32326 * @this {ol.Map}
32327 */
32328 function(interaction) {
32329 interaction.setMap(this);
32330 }, this);
32331
32332 ol.events.listen(this.interactions_, ol.CollectionEventType.ADD,
32333 /**
32334 * @param {ol.Collection.Event} event Collection event.
32335 */
32336 function(event) {
32337 event.element.setMap(this);
32338 }, this);
32339
32340 ol.events.listen(this.interactions_, ol.CollectionEventType.REMOVE,
32341 /**
32342 * @param {ol.Collection.Event} event Collection event.
32343 */
32344 function(event) {
32345 event.element.setMap(null);
32346 }, this);
32347
32348 this.overlays_.forEach(this.addOverlayInternal_, this);
32349
32350 ol.events.listen(this.overlays_, ol.CollectionEventType.ADD,
32351 /**
32352 * @param {ol.Collection.Event} event Collection event.
32353 */
32354 function(event) {
32355 this.addOverlayInternal_(/** @type {ol.Overlay} */ (event.element));
32356 }, this);
32357
32358 ol.events.listen(this.overlays_, ol.CollectionEventType.REMOVE,
32359 /**
32360 * @param {ol.Collection.Event} event Collection event.
32361 */
32362 function(event) {
32363 var overlay = /** @type {ol.Overlay} */ (event.element);
32364 var id = overlay.getId();
32365 if (id !== undefined) {
32366 delete this.overlayIdIndex_[id.toString()];
32367 }
32368 event.element.setMap(null);
32369 }, this);
32370
32371};
32372ol.inherits(ol.Map, ol.Object);
32373
32374
32375/**
32376 * Add the given control to the map.
32377 * @param {ol.control.Control} control Control.
32378 * @api
32379 */
32380ol.Map.prototype.addControl = function(control) {
32381 this.getControls().push(control);
32382};
32383
32384
32385/**
32386 * Add the given interaction to the map.
32387 * @param {ol.interaction.Interaction} interaction Interaction to add.
32388 * @api
32389 */
32390ol.Map.prototype.addInteraction = function(interaction) {
32391 this.getInteractions().push(interaction);
32392};
32393
32394
32395/**
32396 * Adds the given layer to the top of this map. If you want to add a layer
32397 * elsewhere in the stack, use `getLayers()` and the methods available on
32398 * {@link ol.Collection}.
32399 * @param {ol.layer.Base} layer Layer.
32400 * @api
32401 */
32402ol.Map.prototype.addLayer = function(layer) {
32403 var layers = this.getLayerGroup().getLayers();
32404 layers.push(layer);
32405};
32406
32407
32408/**
32409 * Add the given overlay to the map.
32410 * @param {ol.Overlay} overlay Overlay.
32411 * @api
32412 */
32413ol.Map.prototype.addOverlay = function(overlay) {
32414 this.getOverlays().push(overlay);
32415};
32416
32417
32418/**
32419 * This deals with map's overlay collection changes.
32420 * @param {ol.Overlay} overlay Overlay.
32421 * @private
32422 */
32423ol.Map.prototype.addOverlayInternal_ = function(overlay) {
32424 var id = overlay.getId();
32425 if (id !== undefined) {
32426 this.overlayIdIndex_[id.toString()] = overlay;
32427 }
32428 overlay.setMap(this);
32429};
32430
32431
32432/**
32433 *
32434 * @inheritDoc
32435 */
32436ol.Map.prototype.disposeInternal = function() {
32437 this.mapBrowserEventHandler_.dispose();
32438 this.renderer_.dispose();
32439 ol.events.unlisten(this.viewport_, ol.events.EventType.WHEEL,
32440 this.handleBrowserEvent, this);
32441 ol.events.unlisten(this.viewport_, ol.events.EventType.MOUSEWHEEL,
32442 this.handleBrowserEvent, this);
32443 if (this.handleResize_ !== undefined) {
32444 window.removeEventListener(ol.events.EventType.RESIZE,
32445 this.handleResize_, false);
32446 this.handleResize_ = undefined;
32447 }
32448 if (this.animationDelayKey_) {
32449 cancelAnimationFrame(this.animationDelayKey_);
32450 this.animationDelayKey_ = undefined;
32451 }
32452 this.setTarget(null);
32453 ol.Object.prototype.disposeInternal.call(this);
32454};
32455
32456
32457/**
32458 * Detect features that intersect a pixel on the viewport, and execute a
32459 * callback with each intersecting feature. Layers included in the detection can
32460 * be configured through the `layerFilter` option in `opt_options`.
32461 * @param {ol.Pixel} pixel Pixel.
32462 * @param {function(this: S, (ol.Feature|ol.render.Feature),
32463 * ol.layer.Layer): T} callback Feature callback. The callback will be
32464 * called with two arguments. The first argument is one
32465 * {@link ol.Feature feature} or
32466 * {@link ol.render.Feature render feature} at the pixel, the second is
32467 * the {@link ol.layer.Layer layer} of the feature and will be null for
32468 * unmanaged layers. To stop detection, callback functions can return a
32469 * truthy value.
32470 * @param {olx.AtPixelOptions=} opt_options Optional options.
32471 * @return {T|undefined} Callback result, i.e. the return value of last
32472 * callback execution, or the first truthy callback return value.
32473 * @template S,T
32474 * @api
32475 */
32476ol.Map.prototype.forEachFeatureAtPixel = function(pixel, callback, opt_options) {
32477 if (!this.frameState_) {
32478 return;
32479 }
32480 var coordinate = this.getCoordinateFromPixel(pixel);
32481 opt_options = opt_options !== undefined ? opt_options : {};
32482 var hitTolerance = opt_options.hitTolerance !== undefined ?
32483 opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
32484 var layerFilter = opt_options.layerFilter !== undefined ?
32485 opt_options.layerFilter : ol.functions.TRUE;
32486 return this.renderer_.forEachFeatureAtCoordinate(
32487 coordinate, this.frameState_, hitTolerance, callback, null,
32488 layerFilter, null);
32489};
32490
32491
32492/**
32493 * Get all features that intersect a pixel on the viewport.
32494 * @param {ol.Pixel} pixel Pixel.
32495 * @param {olx.AtPixelOptions=} opt_options Optional options.
32496 * @return {Array.<ol.Feature|ol.render.Feature>} The detected features or
32497 * `null` if none were found.
32498 * @api
32499 */
32500ol.Map.prototype.getFeaturesAtPixel = function(pixel, opt_options) {
32501 var features = null;
32502 this.forEachFeatureAtPixel(pixel, function(feature) {
32503 if (!features) {
32504 features = [];
32505 }
32506 features.push(feature);
32507 }, opt_options);
32508 return features;
32509};
32510
32511/**
32512 * Detect layers that have a color value at a pixel on the viewport, and
32513 * execute a callback with each matching layer. Layers included in the
32514 * detection can be configured through `opt_layerFilter`.
32515 * @param {ol.Pixel} pixel Pixel.
32516 * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback
32517 * Layer callback. This callback will receive two arguments: first is the
32518 * {@link ol.layer.Layer layer}, second argument is an array representing
32519 * [R, G, B, A] pixel values (0 - 255) and will be `null` for layer types
32520 * that do not currently support this argument. To stop detection, callback
32521 * functions can return a truthy value.
32522 * @param {S=} opt_this Value to use as `this` when executing `callback`.
32523 * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
32524 * filter function. The filter function will receive one argument, the
32525 * {@link ol.layer.Layer layer-candidate} and it should return a boolean
32526 * value. Only layers which are visible and for which this function returns
32527 * `true` will be tested for features. By default, all visible layers will
32528 * be tested.
32529 * @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
32530 * @return {T|undefined} Callback result, i.e. the return value of last
32531 * callback execution, or the first truthy callback return value.
32532 * @template S,T,U
32533 * @api
32534 */
32535ol.Map.prototype.forEachLayerAtPixel = function(pixel, callback, opt_this, opt_layerFilter, opt_this2) {
32536 if (!this.frameState_) {
32537 return;
32538 }
32539 var thisArg = opt_this !== undefined ? opt_this : null;
32540 var layerFilter = opt_layerFilter !== undefined ?
32541 opt_layerFilter : ol.functions.TRUE;
32542 var thisArg2 = opt_this2 !== undefined ? opt_this2 : null;
32543 return this.renderer_.forEachLayerAtPixel(
32544 pixel, this.frameState_, callback, thisArg,
32545 layerFilter, thisArg2);
32546};
32547
32548
32549/**
32550 * Detect if features intersect a pixel on the viewport. Layers included in the
32551 * detection can be configured through `opt_layerFilter`.
32552 * @param {ol.Pixel} pixel Pixel.
32553 * @param {olx.AtPixelOptions=} opt_options Optional options.
32554 * @return {boolean} Is there a feature at the given pixel?
32555 * @template U
32556 * @api
32557 */
32558ol.Map.prototype.hasFeatureAtPixel = function(pixel, opt_options) {
32559 if (!this.frameState_) {
32560 return false;
32561 }
32562 var coordinate = this.getCoordinateFromPixel(pixel);
32563 opt_options = opt_options !== undefined ? opt_options : {};
32564 var layerFilter = opt_options.layerFilter !== undefined ?
32565 opt_options.layerFilter : ol.functions.TRUE;
32566 var hitTolerance = opt_options.hitTolerance !== undefined ?
32567 opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
32568 return this.renderer_.hasFeatureAtCoordinate(
32569 coordinate, this.frameState_, hitTolerance, layerFilter, null);
32570};
32571
32572
32573/**
32574 * Returns the coordinate in view projection for a browser event.
32575 * @param {Event} event Event.
32576 * @return {ol.Coordinate} Coordinate.
32577 * @api
32578 */
32579ol.Map.prototype.getEventCoordinate = function(event) {
32580 return this.getCoordinateFromPixel(this.getEventPixel(event));
32581};
32582
32583
32584/**
32585 * Returns the map pixel position for a browser event relative to the viewport.
32586 * @param {Event} event Event.
32587 * @return {ol.Pixel} Pixel.
32588 * @api
32589 */
32590ol.Map.prototype.getEventPixel = function(event) {
32591 var viewportPosition = this.viewport_.getBoundingClientRect();
32592 var eventPosition = event.changedTouches ? event.changedTouches[0] : event;
32593 return [
32594 eventPosition.clientX - viewportPosition.left,
32595 eventPosition.clientY - viewportPosition.top
32596 ];
32597};
32598
32599
32600/**
32601 * Get the target in which this map is rendered.
32602 * Note that this returns what is entered as an option or in setTarget:
32603 * if that was an element, it returns an element; if a string, it returns that.
32604 * @return {Element|string|undefined} The Element or id of the Element that the
32605 * map is rendered in.
32606 * @observable
32607 * @api
32608 */
32609ol.Map.prototype.getTarget = function() {
32610 return /** @type {Element|string|undefined} */ (
32611 this.get(ol.MapProperty.TARGET));
32612};
32613
32614
32615/**
32616 * Get the DOM element into which this map is rendered. In contrast to
32617 * `getTarget` this method always return an `Element`, or `null` if the
32618 * map has no target.
32619 * @return {Element} The element that the map is rendered in.
32620 * @api
32621 */
32622ol.Map.prototype.getTargetElement = function() {
32623 var target = this.getTarget();
32624 if (target !== undefined) {
32625 return typeof target === 'string' ?
32626 document.getElementById(target) :
32627 target;
32628 } else {
32629 return null;
32630 }
32631};
32632
32633
32634/**
32635 * Get the coordinate for a given pixel. This returns a coordinate in the
32636 * map view projection.
32637 * @param {ol.Pixel} pixel Pixel position in the map viewport.
32638 * @return {ol.Coordinate} The coordinate for the pixel position.
32639 * @api
32640 */
32641ol.Map.prototype.getCoordinateFromPixel = function(pixel) {
32642 var frameState = this.frameState_;
32643 if (!frameState) {
32644 return null;
32645 } else {
32646 return ol.transform.apply(frameState.pixelToCoordinateTransform, pixel.slice());
32647 }
32648};
32649
32650
32651/**
32652 * Get the map controls. Modifying this collection changes the controls
32653 * associated with the map.
32654 * @return {ol.Collection.<ol.control.Control>} Controls.
32655 * @api
32656 */
32657ol.Map.prototype.getControls = function() {
32658 return this.controls_;
32659};
32660
32661
32662/**
32663 * Get the map overlays. Modifying this collection changes the overlays
32664 * associated with the map.
32665 * @return {ol.Collection.<ol.Overlay>} Overlays.
32666 * @api
32667 */
32668ol.Map.prototype.getOverlays = function() {
32669 return this.overlays_;
32670};
32671
32672
32673/**
32674 * Get an overlay by its identifier (the value returned by overlay.getId()).
32675 * Note that the index treats string and numeric identifiers as the same. So
32676 * `map.getOverlayById(2)` will return an overlay with id `'2'` or `2`.
32677 * @param {string|number} id Overlay identifier.
32678 * @return {ol.Overlay} Overlay.
32679 * @api
32680 */
32681ol.Map.prototype.getOverlayById = function(id) {
32682 var overlay = this.overlayIdIndex_[id.toString()];
32683 return overlay !== undefined ? overlay : null;
32684};
32685
32686
32687/**
32688 * Get the map interactions. Modifying this collection changes the interactions
32689 * associated with the map.
32690 *
32691 * Interactions are used for e.g. pan, zoom and rotate.
32692 * @return {ol.Collection.<ol.interaction.Interaction>} Interactions.
32693 * @api
32694 */
32695ol.Map.prototype.getInteractions = function() {
32696 return this.interactions_;
32697};
32698
32699
32700/**
32701 * Get the layergroup associated with this map.
32702 * @return {ol.layer.Group} A layer group containing the layers in this map.
32703 * @observable
32704 * @api
32705 */
32706ol.Map.prototype.getLayerGroup = function() {
32707 return /** @type {ol.layer.Group} */ (this.get(ol.MapProperty.LAYERGROUP));
32708};
32709
32710
32711/**
32712 * Get the collection of layers associated with this map.
32713 * @return {!ol.Collection.<ol.layer.Base>} Layers.
32714 * @api
32715 */
32716ol.Map.prototype.getLayers = function() {
32717 var layers = this.getLayerGroup().getLayers();
32718 return layers;
32719};
32720
32721
32722/**
32723 * Get the pixel for a coordinate. This takes a coordinate in the map view
32724 * projection and returns the corresponding pixel.
32725 * @param {ol.Coordinate} coordinate A map coordinate.
32726 * @return {ol.Pixel} A pixel position in the map viewport.
32727 * @api
32728 */
32729ol.Map.prototype.getPixelFromCoordinate = function(coordinate) {
32730 var frameState = this.frameState_;
32731 if (!frameState) {
32732 return null;
32733 } else {
32734 return ol.transform.apply(frameState.coordinateToPixelTransform,
32735 coordinate.slice(0, 2));
32736 }
32737};
32738
32739
32740/**
32741 * Get the map renderer.
32742 * @return {ol.renderer.Map} Renderer
32743 */
32744ol.Map.prototype.getRenderer = function() {
32745 return this.renderer_;
32746};
32747
32748
32749/**
32750 * Get the size of this map.
32751 * @return {ol.Size|undefined} The size in pixels of the map in the DOM.
32752 * @observable
32753 * @api
32754 */
32755ol.Map.prototype.getSize = function() {
32756 return /** @type {ol.Size|undefined} */ (this.get(ol.MapProperty.SIZE));
32757};
32758
32759
32760/**
32761 * Get the view associated with this map. A view manages properties such as
32762 * center and resolution.
32763 * @return {ol.View} The view that controls this map.
32764 * @observable
32765 * @api
32766 */
32767ol.Map.prototype.getView = function() {
32768 return /** @type {ol.View} */ (this.get(ol.MapProperty.VIEW));
32769};
32770
32771
32772/**
32773 * Get the element that serves as the map viewport.
32774 * @return {Element} Viewport.
32775 * @api
32776 */
32777ol.Map.prototype.getViewport = function() {
32778 return this.viewport_;
32779};
32780
32781
32782/**
32783 * Get the element that serves as the container for overlays. Elements added to
32784 * this container will let mousedown and touchstart events through to the map,
32785 * so clicks and gestures on an overlay will trigger {@link ol.MapBrowserEvent}
32786 * events.
32787 * @return {!Element} The map's overlay container.
32788 */
32789ol.Map.prototype.getOverlayContainer = function() {
32790 return this.overlayContainer_;
32791};
32792
32793
32794/**
32795 * Get the element that serves as a container for overlays that don't allow
32796 * event propagation. Elements added to this container won't let mousedown and
32797 * touchstart events through to the map, so clicks and gestures on an overlay
32798 * don't trigger any {@link ol.MapBrowserEvent}.
32799 * @return {!Element} The map's overlay container that stops events.
32800 */
32801ol.Map.prototype.getOverlayContainerStopEvent = function() {
32802 return this.overlayContainerStopEvent_;
32803};
32804
32805
32806/**
32807 * @param {ol.Tile} tile Tile.
32808 * @param {string} tileSourceKey Tile source key.
32809 * @param {ol.Coordinate} tileCenter Tile center.
32810 * @param {number} tileResolution Tile resolution.
32811 * @return {number} Tile priority.
32812 */
32813ol.Map.prototype.getTilePriority = function(tile, tileSourceKey, tileCenter, tileResolution) {
32814 // Filter out tiles at higher zoom levels than the current zoom level, or that
32815 // are outside the visible extent.
32816 var frameState = this.frameState_;
32817 if (!frameState || !(tileSourceKey in frameState.wantedTiles)) {
32818 return ol.structs.PriorityQueue.DROP;
32819 }
32820 if (!frameState.wantedTiles[tileSourceKey][tile.getKey()]) {
32821 return ol.structs.PriorityQueue.DROP;
32822 }
32823 // Prioritize the highest zoom level tiles closest to the focus.
32824 // Tiles at higher zoom levels are prioritized using Math.log(tileResolution).
32825 // Within a zoom level, tiles are prioritized by the distance in pixels
32826 // between the center of the tile and the focus. The factor of 65536 means
32827 // that the prioritization should behave as desired for tiles up to
32828 // 65536 * Math.log(2) = 45426 pixels from the focus.
32829 var deltaX = tileCenter[0] - frameState.focus[0];
32830 var deltaY = tileCenter[1] - frameState.focus[1];
32831 return 65536 * Math.log(tileResolution) +
32832 Math.sqrt(deltaX * deltaX + deltaY * deltaY) / tileResolution;
32833};
32834
32835
32836/**
32837 * @param {Event} browserEvent Browser event.
32838 * @param {string=} opt_type Type.
32839 */
32840ol.Map.prototype.handleBrowserEvent = function(browserEvent, opt_type) {
32841 var type = opt_type || browserEvent.type;
32842 var mapBrowserEvent = new ol.MapBrowserEvent(type, this, browserEvent);
32843 this.handleMapBrowserEvent(mapBrowserEvent);
32844};
32845
32846
32847/**
32848 * @param {ol.MapBrowserEvent} mapBrowserEvent The event to handle.
32849 */
32850ol.Map.prototype.handleMapBrowserEvent = function(mapBrowserEvent) {
32851 if (!this.frameState_) {
32852 // With no view defined, we cannot translate pixels into geographical
32853 // coordinates so interactions cannot be used.
32854 return;
32855 }
32856 this.focus_ = mapBrowserEvent.coordinate;
32857 mapBrowserEvent.frameState = this.frameState_;
32858 var interactionsArray = this.getInteractions().getArray();
32859 var i;
32860 if (this.dispatchEvent(mapBrowserEvent) !== false) {
32861 for (i = interactionsArray.length - 1; i >= 0; i--) {
32862 var interaction = interactionsArray[i];
32863 if (!interaction.getActive()) {
32864 continue;
32865 }
32866 var cont = interaction.handleEvent(mapBrowserEvent);
32867 if (!cont) {
32868 break;
32869 }
32870 }
32871 }
32872};
32873
32874
32875/**
32876 * @protected
32877 */
32878ol.Map.prototype.handlePostRender = function() {
32879
32880 var frameState = this.frameState_;
32881
32882 // Manage the tile queue
32883 // Image loads are expensive and a limited resource, so try to use them
32884 // efficiently:
32885 // * When the view is static we allow a large number of parallel tile loads
32886 // to complete the frame as quickly as possible.
32887 // * When animating or interacting, image loads can cause janks, so we reduce
32888 // the maximum number of loads per frame and limit the number of parallel
32889 // tile loads to remain reactive to view changes and to reduce the chance of
32890 // loading tiles that will quickly disappear from view.
32891 var tileQueue = this.tileQueue_;
32892 if (!tileQueue.isEmpty()) {
32893 var maxTotalLoading = 16;
32894 var maxNewLoads = maxTotalLoading;
32895 if (frameState) {
32896 var hints = frameState.viewHints;
32897 if (hints[ol.ViewHint.ANIMATING]) {
32898 maxTotalLoading = this.loadTilesWhileAnimating_ ? 8 : 0;
32899 maxNewLoads = 2;
32900 }
32901 if (hints[ol.ViewHint.INTERACTING]) {
32902 maxTotalLoading = this.loadTilesWhileInteracting_ ? 8 : 0;
32903 maxNewLoads = 2;
32904 }
32905 }
32906 if (tileQueue.getTilesLoading() < maxTotalLoading) {
32907 tileQueue.reprioritize(); // FIXME only call if view has changed
32908 tileQueue.loadMoreTiles(maxTotalLoading, maxNewLoads);
32909 }
32910 }
32911
32912 var postRenderFunctions = this.postRenderFunctions_;
32913 var i, ii;
32914 for (i = 0, ii = postRenderFunctions.length; i < ii; ++i) {
32915 postRenderFunctions[i](this, frameState);
32916 }
32917 postRenderFunctions.length = 0;
32918};
32919
32920
32921/**
32922 * @private
32923 */
32924ol.Map.prototype.handleSizeChanged_ = function() {
32925 this.render();
32926};
32927
32928
32929/**
32930 * @private
32931 */
32932ol.Map.prototype.handleTargetChanged_ = function() {
32933 // target may be undefined, null, a string or an Element.
32934 // If it's a string we convert it to an Element before proceeding.
32935 // If it's not now an Element we remove the viewport from the DOM.
32936 // If it's an Element we append the viewport element to it.
32937
32938 var targetElement;
32939 if (this.getTarget()) {
32940 targetElement = this.getTargetElement();
32941 }
32942
32943 if (this.keyHandlerKeys_) {
32944 for (var i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
32945 ol.events.unlistenByKey(this.keyHandlerKeys_[i]);
32946 }
32947 this.keyHandlerKeys_ = null;
32948 }
32949
32950 if (!targetElement) {
32951 ol.dom.removeNode(this.viewport_);
32952 if (this.handleResize_ !== undefined) {
32953 window.removeEventListener(ol.events.EventType.RESIZE,
32954 this.handleResize_, false);
32955 this.handleResize_ = undefined;
32956 }
32957 } else {
32958 targetElement.appendChild(this.viewport_);
32959
32960 var keyboardEventTarget = !this.keyboardEventTarget_ ?
32961 targetElement : this.keyboardEventTarget_;
32962 this.keyHandlerKeys_ = [
32963 ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYDOWN,
32964 this.handleBrowserEvent, this),
32965 ol.events.listen(keyboardEventTarget, ol.events.EventType.KEYPRESS,
32966 this.handleBrowserEvent, this)
32967 ];
32968
32969 if (!this.handleResize_) {
32970 this.handleResize_ = this.updateSize.bind(this);
32971 window.addEventListener(ol.events.EventType.RESIZE,
32972 this.handleResize_, false);
32973 }
32974 }
32975
32976 this.updateSize();
32977 // updateSize calls setSize, so no need to call this.render
32978 // ourselves here.
32979};
32980
32981
32982/**
32983 * @private
32984 */
32985ol.Map.prototype.handleTileChange_ = function() {
32986 this.render();
32987};
32988
32989
32990/**
32991 * @private
32992 */
32993ol.Map.prototype.handleViewPropertyChanged_ = function() {
32994 this.render();
32995};
32996
32997
32998/**
32999 * @private
33000 */
33001ol.Map.prototype.handleViewChanged_ = function() {
33002 if (this.viewPropertyListenerKey_) {
33003 ol.events.unlistenByKey(this.viewPropertyListenerKey_);
33004 this.viewPropertyListenerKey_ = null;
33005 }
33006 if (this.viewChangeListenerKey_) {
33007 ol.events.unlistenByKey(this.viewChangeListenerKey_);
33008 this.viewChangeListenerKey_ = null;
33009 }
33010 var view = this.getView();
33011 if (view) {
33012 this.viewport_.setAttribute('data-view', ol.getUid(view));
33013 this.viewPropertyListenerKey_ = ol.events.listen(
33014 view, ol.ObjectEventType.PROPERTYCHANGE,
33015 this.handleViewPropertyChanged_, this);
33016 this.viewChangeListenerKey_ = ol.events.listen(
33017 view, ol.events.EventType.CHANGE,
33018 this.handleViewPropertyChanged_, this);
33019 }
33020 this.render();
33021};
33022
33023
33024/**
33025 * @private
33026 */
33027ol.Map.prototype.handleLayerGroupChanged_ = function() {
33028 if (this.layerGroupPropertyListenerKeys_) {
33029 this.layerGroupPropertyListenerKeys_.forEach(ol.events.unlistenByKey);
33030 this.layerGroupPropertyListenerKeys_ = null;
33031 }
33032 var layerGroup = this.getLayerGroup();
33033 if (layerGroup) {
33034 this.layerGroupPropertyListenerKeys_ = [
33035 ol.events.listen(
33036 layerGroup, ol.ObjectEventType.PROPERTYCHANGE,
33037 this.render, this),
33038 ol.events.listen(
33039 layerGroup, ol.events.EventType.CHANGE,
33040 this.render, this)
33041 ];
33042 }
33043 this.render();
33044};
33045
33046
33047/**
33048 * @return {boolean} Is rendered.
33049 */
33050ol.Map.prototype.isRendered = function() {
33051 return !!this.frameState_;
33052};
33053
33054
33055/**
33056 * Requests an immediate render in a synchronous manner.
33057 * @api
33058 */
33059ol.Map.prototype.renderSync = function() {
33060 if (this.animationDelayKey_) {
33061 cancelAnimationFrame(this.animationDelayKey_);
33062 }
33063 this.animationDelay_();
33064};
33065
33066
33067/**
33068 * Request a map rendering (at the next animation frame).
33069 * @api
33070 */
33071ol.Map.prototype.render = function() {
33072 if (this.animationDelayKey_ === undefined) {
33073 this.animationDelayKey_ = requestAnimationFrame(
33074 this.animationDelay_);
33075 }
33076};
33077
33078
33079/**
33080 * Remove the given control from the map.
33081 * @param {ol.control.Control} control Control.
33082 * @return {ol.control.Control|undefined} The removed control (or undefined
33083 * if the control was not found).
33084 * @api
33085 */
33086ol.Map.prototype.removeControl = function(control) {
33087 return this.getControls().remove(control);
33088};
33089
33090
33091/**
33092 * Remove the given interaction from the map.
33093 * @param {ol.interaction.Interaction} interaction Interaction to remove.
33094 * @return {ol.interaction.Interaction|undefined} The removed interaction (or
33095 * undefined if the interaction was not found).
33096 * @api
33097 */
33098ol.Map.prototype.removeInteraction = function(interaction) {
33099 return this.getInteractions().remove(interaction);
33100};
33101
33102
33103/**
33104 * Removes the given layer from the map.
33105 * @param {ol.layer.Base} layer Layer.
33106 * @return {ol.layer.Base|undefined} The removed layer (or undefined if the
33107 * layer was not found).
33108 * @api
33109 */
33110ol.Map.prototype.removeLayer = function(layer) {
33111 var layers = this.getLayerGroup().getLayers();
33112 return layers.remove(layer);
33113};
33114
33115
33116/**
33117 * Remove the given overlay from the map.
33118 * @param {ol.Overlay} overlay Overlay.
33119 * @return {ol.Overlay|undefined} The removed overlay (or undefined
33120 * if the overlay was not found).
33121 * @api
33122 */
33123ol.Map.prototype.removeOverlay = function(overlay) {
33124 return this.getOverlays().remove(overlay);
33125};
33126
33127
33128/**
33129 * @param {number} time Time.
33130 * @private
33131 */
33132ol.Map.prototype.renderFrame_ = function(time) {
33133 var i, ii, viewState;
33134
33135 var size = this.getSize();
33136 var view = this.getView();
33137 var extent = ol.extent.createEmpty();
33138 var previousFrameState = this.frameState_;
33139 /** @type {?olx.FrameState} */
33140 var frameState = null;
33141 if (size !== undefined && ol.size.hasArea(size) && view && view.isDef()) {
33142 var viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);
33143 var layerStatesArray = this.getLayerGroup().getLayerStatesArray();
33144 var layerStates = {};
33145 for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
33146 layerStates[ol.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
33147 }
33148 viewState = view.getState();
33149 frameState = /** @type {olx.FrameState} */ ({
33150 animate: false,
33151 attributions: {},
33152 coordinateToPixelTransform: this.coordinateToPixelTransform_,
33153 extent: extent,
33154 focus: !this.focus_ ? viewState.center : this.focus_,
33155 index: this.frameIndex_++,
33156 layerStates: layerStates,
33157 layerStatesArray: layerStatesArray,
33158 logos: ol.obj.assign({}, this.logos_),
33159 pixelRatio: this.pixelRatio_,
33160 pixelToCoordinateTransform: this.pixelToCoordinateTransform_,
33161 postRenderFunctions: [],
33162 size: size,
33163 skippedFeatureUids: this.skippedFeatureUids_,
33164 tileQueue: this.tileQueue_,
33165 time: time,
33166 usedTiles: {},
33167 viewState: viewState,
33168 viewHints: viewHints,
33169 wantedTiles: {}
33170 });
33171 }
33172
33173 if (frameState) {
33174 frameState.extent = ol.extent.getForViewAndSize(viewState.center,
33175 viewState.resolution, viewState.rotation, frameState.size, extent);
33176 }
33177
33178 this.frameState_ = frameState;
33179 this.renderer_.renderFrame(frameState);
33180
33181 if (frameState) {
33182 if (frameState.animate) {
33183 this.render();
33184 }
33185 Array.prototype.push.apply(
33186 this.postRenderFunctions_, frameState.postRenderFunctions);
33187
33188 if (previousFrameState) {
33189 var moveStart = !this.previousExtent_ ||
33190 (!ol.extent.isEmpty(this.previousExtent_) &&
33191 !ol.extent.equals(frameState.extent, this.previousExtent_));
33192 if (moveStart) {
33193 this.dispatchEvent(
33194 new ol.MapEvent(ol.MapEventType.MOVESTART, this, previousFrameState));
33195 this.previousExtent_ = ol.extent.createOrUpdateEmpty(this.previousExtent_);
33196 }
33197 }
33198
33199 var idle = this.previousExtent_ &&
33200 !frameState.viewHints[ol.ViewHint.ANIMATING] &&
33201 !frameState.viewHints[ol.ViewHint.INTERACTING] &&
33202 !ol.extent.equals(frameState.extent, this.previousExtent_);
33203
33204 if (idle) {
33205 this.dispatchEvent(
33206 new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState));
33207 ol.extent.clone(frameState.extent, this.previousExtent_);
33208 }
33209 }
33210
33211 this.dispatchEvent(
33212 new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState));
33213
33214 setTimeout(this.handlePostRender.bind(this), 0);
33215
33216};
33217
33218
33219/**
33220 * Sets the layergroup of this map.
33221 * @param {ol.layer.Group} layerGroup A layer group containing the layers in
33222 * this map.
33223 * @observable
33224 * @api
33225 */
33226ol.Map.prototype.setLayerGroup = function(layerGroup) {
33227 this.set(ol.MapProperty.LAYERGROUP, layerGroup);
33228};
33229
33230
33231/**
33232 * Set the size of this map.
33233 * @param {ol.Size|undefined} size The size in pixels of the map in the DOM.
33234 * @observable
33235 * @api
33236 */
33237ol.Map.prototype.setSize = function(size) {
33238 this.set(ol.MapProperty.SIZE, size);
33239};
33240
33241
33242/**
33243 * Set the target element to render this map into.
33244 * @param {Element|string|undefined} target The Element or id of the Element
33245 * that the map is rendered in.
33246 * @observable
33247 * @api
33248 */
33249ol.Map.prototype.setTarget = function(target) {
33250 this.set(ol.MapProperty.TARGET, target);
33251};
33252
33253
33254/**
33255 * Set the view for this map.
33256 * @param {ol.View} view The view that controls this map.
33257 * @observable
33258 * @api
33259 */
33260ol.Map.prototype.setView = function(view) {
33261 this.set(ol.MapProperty.VIEW, view);
33262};
33263
33264
33265/**
33266 * @param {ol.Feature} feature Feature.
33267 */
33268ol.Map.prototype.skipFeature = function(feature) {
33269 var featureUid = ol.getUid(feature).toString();
33270 this.skippedFeatureUids_[featureUid] = true;
33271 this.render();
33272};
33273
33274
33275/**
33276 * Force a recalculation of the map viewport size. This should be called when
33277 * third-party code changes the size of the map viewport.
33278 * @api
33279 */
33280ol.Map.prototype.updateSize = function() {
33281 var targetElement = this.getTargetElement();
33282
33283 if (!targetElement) {
33284 this.setSize(undefined);
33285 } else {
33286 var computedStyle = getComputedStyle(targetElement);
33287 this.setSize([
33288 targetElement.offsetWidth -
33289 parseFloat(computedStyle['borderLeftWidth']) -
33290 parseFloat(computedStyle['paddingLeft']) -
33291 parseFloat(computedStyle['paddingRight']) -
33292 parseFloat(computedStyle['borderRightWidth']),
33293 targetElement.offsetHeight -
33294 parseFloat(computedStyle['borderTopWidth']) -
33295 parseFloat(computedStyle['paddingTop']) -
33296 parseFloat(computedStyle['paddingBottom']) -
33297 parseFloat(computedStyle['borderBottomWidth'])
33298 ]);
33299 }
33300};
33301
33302
33303/**
33304 * @param {ol.Feature} feature Feature.
33305 */
33306ol.Map.prototype.unskipFeature = function(feature) {
33307 var featureUid = ol.getUid(feature).toString();
33308 delete this.skippedFeatureUids_[featureUid];
33309 this.render();
33310};
33311
33312
33313/**
33314 * @param {olx.MapOptions} options Map options.
33315 * @return {ol.MapOptionsInternal} Internal map options.
33316 */
33317ol.Map.createOptionsInternal = function(options) {
33318
33319 /**
33320 * @type {Element|Document}
33321 */
33322 var keyboardEventTarget = null;
33323 if (options.keyboardEventTarget !== undefined) {
33324 keyboardEventTarget = typeof options.keyboardEventTarget === 'string' ?
33325 document.getElementById(options.keyboardEventTarget) :
33326 options.keyboardEventTarget;
33327 }
33328
33329 /**
33330 * @type {Object.<string, *>}
33331 */
33332 var values = {};
33333
33334 var logos = {};
33335 if (options.logo === undefined ||
33336 (typeof options.logo === 'boolean' && options.logo)) {
33337 logos[ol.OL_LOGO_URL] = ol.OL_URL;
33338 } else {
33339 var logo = options.logo;
33340 if (typeof logo === 'string') {
33341 logos[logo] = '';
33342 } else if (logo instanceof HTMLElement) {
33343 logos[ol.getUid(logo).toString()] = logo;
33344 } else if (logo) {
33345 ol.asserts.assert(typeof logo.href == 'string', 44); // `logo.href` should be a string.
33346 ol.asserts.assert(typeof logo.src == 'string', 45); // `logo.src` should be a string.
33347 logos[logo.src] = logo.href;
33348 }
33349 }
33350
33351 var layerGroup = (options.layers instanceof ol.layer.Group) ?
33352 options.layers : new ol.layer.Group({layers: options.layers});
33353 values[ol.MapProperty.LAYERGROUP] = layerGroup;
33354
33355 values[ol.MapProperty.TARGET] = options.target;
33356
33357 values[ol.MapProperty.VIEW] = options.view !== undefined ?
33358 options.view : new ol.View();
33359
33360 /**
33361 * @type {function(new: ol.renderer.Map, Element, ol.Map)}
33362 */
33363 var rendererConstructor = ol.renderer.Map;
33364
33365 /**
33366 * @type {Array.<ol.renderer.Type>}
33367 */
33368 var rendererTypes;
33369 if (options.renderer !== undefined) {
33370 if (Array.isArray(options.renderer)) {
33371 rendererTypes = options.renderer;
33372 } else if (typeof options.renderer === 'string') {
33373 rendererTypes = [options.renderer];
33374 } else {
33375 ol.asserts.assert(false, 46); // Incorrect format for `renderer` option
33376 }
33377 if (rendererTypes.indexOf(/** @type {ol.renderer.Type} */ ('dom')) >= 0) {
33378 rendererTypes = rendererTypes.concat(ol.DEFAULT_RENDERER_TYPES);
33379 }
33380 } else {
33381 rendererTypes = ol.DEFAULT_RENDERER_TYPES;
33382 }
33383
33384 var i, ii;
33385 for (i = 0, ii = rendererTypes.length; i < ii; ++i) {
33386 /** @type {ol.renderer.Type} */
33387 var rendererType = rendererTypes[i];
33388 if (ol.ENABLE_CANVAS && rendererType == ol.renderer.Type.CANVAS) {
33389 if (ol.has.CANVAS) {
33390 rendererConstructor = ol.renderer.canvas.Map;
33391 break;
33392 }
33393 } else if (ol.ENABLE_WEBGL && rendererType == ol.renderer.Type.WEBGL) {
33394 if (ol.has.WEBGL) {
33395 rendererConstructor = ol.renderer.webgl.Map;
33396 break;
33397 }
33398 }
33399 }
33400
33401 var controls;
33402 if (options.controls !== undefined) {
33403 if (Array.isArray(options.controls)) {
33404 controls = new ol.Collection(options.controls.slice());
33405 } else {
33406 ol.asserts.assert(options.controls instanceof ol.Collection,
33407 47); // Expected `controls` to be an array or an `ol.Collection`
33408 controls = options.controls;
33409 }
33410 } else {
33411 controls = ol.control.defaults();
33412 }
33413
33414 var interactions;
33415 if (options.interactions !== undefined) {
33416 if (Array.isArray(options.interactions)) {
33417 interactions = new ol.Collection(options.interactions.slice());
33418 } else {
33419 ol.asserts.assert(options.interactions instanceof ol.Collection,
33420 48); // Expected `interactions` to be an array or an `ol.Collection`
33421 interactions = options.interactions;
33422 }
33423 } else {
33424 interactions = ol.interaction.defaults();
33425 }
33426
33427 var overlays;
33428 if (options.overlays !== undefined) {
33429 if (Array.isArray(options.overlays)) {
33430 overlays = new ol.Collection(options.overlays.slice());
33431 } else {
33432 ol.asserts.assert(options.overlays instanceof ol.Collection,
33433 49); // Expected `overlays` to be an array or an `ol.Collection`
33434 overlays = options.overlays;
33435 }
33436 } else {
33437 overlays = new ol.Collection();
33438 }
33439
33440 return {
33441 controls: controls,
33442 interactions: interactions,
33443 keyboardEventTarget: keyboardEventTarget,
33444 logos: logos,
33445 overlays: overlays,
33446 rendererConstructor: rendererConstructor,
33447 values: values
33448 };
33449
33450};
33451
33452goog.provide('ol.OverlayPositioning');
33453
33454/**
33455 * Overlay position: `'bottom-left'`, `'bottom-center'`, `'bottom-right'`,
33456 * `'center-left'`, `'center-center'`, `'center-right'`, `'top-left'`,
33457 * `'top-center'`, `'top-right'`
33458 * @enum {string}
33459 */
33460ol.OverlayPositioning = {
33461 BOTTOM_LEFT: 'bottom-left',
33462 BOTTOM_CENTER: 'bottom-center',
33463 BOTTOM_RIGHT: 'bottom-right',
33464 CENTER_LEFT: 'center-left',
33465 CENTER_CENTER: 'center-center',
33466 CENTER_RIGHT: 'center-right',
33467 TOP_LEFT: 'top-left',
33468 TOP_CENTER: 'top-center',
33469 TOP_RIGHT: 'top-right'
33470};
33471
33472goog.provide('ol.Overlay');
33473
33474goog.require('ol');
33475goog.require('ol.MapEventType');
33476goog.require('ol.Object');
33477goog.require('ol.OverlayPositioning');
33478goog.require('ol.css');
33479goog.require('ol.dom');
33480goog.require('ol.events');
33481goog.require('ol.extent');
33482
33483
33484/**
33485 * @classdesc
33486 * An element to be displayed over the map and attached to a single map
33487 * location. Like {@link ol.control.Control}, Overlays are visible widgets.
33488 * Unlike Controls, they are not in a fixed position on the screen, but are tied
33489 * to a geographical coordinate, so panning the map will move an Overlay but not
33490 * a Control.
33491 *
33492 * Example:
33493 *
33494 * var popup = new ol.Overlay({
33495 * element: document.getElementById('popup')
33496 * });
33497 * popup.setPosition(coordinate);
33498 * map.addOverlay(popup);
33499 *
33500 * @constructor
33501 * @extends {ol.Object}
33502 * @param {olx.OverlayOptions} options Overlay options.
33503 * @api
33504 */
33505ol.Overlay = function(options) {
33506
33507 ol.Object.call(this);
33508
33509 /**
33510 * @private
33511 * @type {number|string|undefined}
33512 */
33513 this.id_ = options.id;
33514
33515 /**
33516 * @private
33517 * @type {boolean}
33518 */
33519 this.insertFirst_ = options.insertFirst !== undefined ?
33520 options.insertFirst : true;
33521
33522 /**
33523 * @private
33524 * @type {boolean}
33525 */
33526 this.stopEvent_ = options.stopEvent !== undefined ? options.stopEvent : true;
33527
33528 /**
33529 * @private
33530 * @type {Element}
33531 */
33532 this.element_ = document.createElement('DIV');
33533 this.element_.className = 'ol-overlay-container ' + ol.css.CLASS_SELECTABLE;
33534 this.element_.style.position = 'absolute';
33535
33536 /**
33537 * @protected
33538 * @type {boolean}
33539 */
33540 this.autoPan = options.autoPan !== undefined ? options.autoPan : false;
33541
33542 /**
33543 * @private
33544 * @type {olx.OverlayPanOptions}
33545 */
33546 this.autoPanAnimation_ = options.autoPanAnimation ||
33547 /** @type {olx.OverlayPanOptions} */ ({});
33548
33549 /**
33550 * @private
33551 * @type {number}
33552 */
33553 this.autoPanMargin_ = options.autoPanMargin !== undefined ?
33554 options.autoPanMargin : 20;
33555
33556 /**
33557 * @private
33558 * @type {{bottom_: string,
33559 * left_: string,
33560 * right_: string,
33561 * top_: string,
33562 * visible: boolean}}
33563 */
33564 this.rendered_ = {
33565 bottom_: '',
33566 left_: '',
33567 right_: '',
33568 top_: '',
33569 visible: true
33570 };
33571
33572 /**
33573 * @private
33574 * @type {?ol.EventsKey}
33575 */
33576 this.mapPostrenderListenerKey_ = null;
33577
33578 ol.events.listen(
33579 this, ol.Object.getChangeEventType(ol.Overlay.Property_.ELEMENT),
33580 this.handleElementChanged, this);
33581
33582 ol.events.listen(
33583 this, ol.Object.getChangeEventType(ol.Overlay.Property_.MAP),
33584 this.handleMapChanged, this);
33585
33586 ol.events.listen(
33587 this, ol.Object.getChangeEventType(ol.Overlay.Property_.OFFSET),
33588 this.handleOffsetChanged, this);
33589
33590 ol.events.listen(
33591 this, ol.Object.getChangeEventType(ol.Overlay.Property_.POSITION),
33592 this.handlePositionChanged, this);
33593
33594 ol.events.listen(
33595 this, ol.Object.getChangeEventType(ol.Overlay.Property_.POSITIONING),
33596 this.handlePositioningChanged, this);
33597
33598 if (options.element !== undefined) {
33599 this.setElement(options.element);
33600 }
33601
33602 this.setOffset(options.offset !== undefined ? options.offset : [0, 0]);
33603
33604 this.setPositioning(options.positioning !== undefined ?
33605 /** @type {ol.OverlayPositioning} */ (options.positioning) :
33606 ol.OverlayPositioning.TOP_LEFT);
33607
33608 if (options.position !== undefined) {
33609 this.setPosition(options.position);
33610 }
33611
33612};
33613ol.inherits(ol.Overlay, ol.Object);
33614
33615
33616/**
33617 * Get the DOM element of this overlay.
33618 * @return {Element|undefined} The Element containing the overlay.
33619 * @observable
33620 * @api
33621 */
33622ol.Overlay.prototype.getElement = function() {
33623 return /** @type {Element|undefined} */ (
33624 this.get(ol.Overlay.Property_.ELEMENT));
33625};
33626
33627
33628/**
33629 * Get the overlay identifier which is set on constructor.
33630 * @return {number|string|undefined} Id.
33631 * @api
33632 */
33633ol.Overlay.prototype.getId = function() {
33634 return this.id_;
33635};
33636
33637
33638/**
33639 * Get the map associated with this overlay.
33640 * @return {ol.Map|undefined} The map that the overlay is part of.
33641 * @observable
33642 * @api
33643 */
33644ol.Overlay.prototype.getMap = function() {
33645 return /** @type {ol.Map|undefined} */ (
33646 this.get(ol.Overlay.Property_.MAP));
33647};
33648
33649
33650/**
33651 * Get the offset of this overlay.
33652 * @return {Array.<number>} The offset.
33653 * @observable
33654 * @api
33655 */
33656ol.Overlay.prototype.getOffset = function() {
33657 return /** @type {Array.<number>} */ (
33658 this.get(ol.Overlay.Property_.OFFSET));
33659};
33660
33661
33662/**
33663 * Get the current position of this overlay.
33664 * @return {ol.Coordinate|undefined} The spatial point that the overlay is
33665 * anchored at.
33666 * @observable
33667 * @api
33668 */
33669ol.Overlay.prototype.getPosition = function() {
33670 return /** @type {ol.Coordinate|undefined} */ (
33671 this.get(ol.Overlay.Property_.POSITION));
33672};
33673
33674
33675/**
33676 * Get the current positioning of this overlay.
33677 * @return {ol.OverlayPositioning} How the overlay is positioned
33678 * relative to its point on the map.
33679 * @observable
33680 * @api
33681 */
33682ol.Overlay.prototype.getPositioning = function() {
33683 return /** @type {ol.OverlayPositioning} */ (
33684 this.get(ol.Overlay.Property_.POSITIONING));
33685};
33686
33687
33688/**
33689 * @protected
33690 */
33691ol.Overlay.prototype.handleElementChanged = function() {
33692 ol.dom.removeChildren(this.element_);
33693 var element = this.getElement();
33694 if (element) {
33695 this.element_.appendChild(element);
33696 }
33697};
33698
33699
33700/**
33701 * @protected
33702 */
33703ol.Overlay.prototype.handleMapChanged = function() {
33704 if (this.mapPostrenderListenerKey_) {
33705 ol.dom.removeNode(this.element_);
33706 ol.events.unlistenByKey(this.mapPostrenderListenerKey_);
33707 this.mapPostrenderListenerKey_ = null;
33708 }
33709 var map = this.getMap();
33710 if (map) {
33711 this.mapPostrenderListenerKey_ = ol.events.listen(map,
33712 ol.MapEventType.POSTRENDER, this.render, this);
33713 this.updatePixelPosition();
33714 var container = this.stopEvent_ ?
33715 map.getOverlayContainerStopEvent() : map.getOverlayContainer();
33716 if (this.insertFirst_) {
33717 container.insertBefore(this.element_, container.childNodes[0] || null);
33718 } else {
33719 container.appendChild(this.element_);
33720 }
33721 }
33722};
33723
33724
33725/**
33726 * @protected
33727 */
33728ol.Overlay.prototype.render = function() {
33729 this.updatePixelPosition();
33730};
33731
33732
33733/**
33734 * @protected
33735 */
33736ol.Overlay.prototype.handleOffsetChanged = function() {
33737 this.updatePixelPosition();
33738};
33739
33740
33741/**
33742 * @protected
33743 */
33744ol.Overlay.prototype.handlePositionChanged = function() {
33745 this.updatePixelPosition();
33746 if (this.get(ol.Overlay.Property_.POSITION) && this.autoPan) {
33747 this.panIntoView_();
33748 }
33749};
33750
33751
33752/**
33753 * @protected
33754 */
33755ol.Overlay.prototype.handlePositioningChanged = function() {
33756 this.updatePixelPosition();
33757};
33758
33759
33760/**
33761 * Set the DOM element to be associated with this overlay.
33762 * @param {Element|undefined} element The Element containing the overlay.
33763 * @observable
33764 * @api
33765 */
33766ol.Overlay.prototype.setElement = function(element) {
33767 this.set(ol.Overlay.Property_.ELEMENT, element);
33768};
33769
33770
33771/**
33772 * Set the map to be associated with this overlay.
33773 * @param {ol.Map|undefined} map The map that the overlay is part of.
33774 * @observable
33775 * @api
33776 */
33777ol.Overlay.prototype.setMap = function(map) {
33778 this.set(ol.Overlay.Property_.MAP, map);
33779};
33780
33781
33782/**
33783 * Set the offset for this overlay.
33784 * @param {Array.<number>} offset Offset.
33785 * @observable
33786 * @api
33787 */
33788ol.Overlay.prototype.setOffset = function(offset) {
33789 this.set(ol.Overlay.Property_.OFFSET, offset);
33790};
33791
33792
33793/**
33794 * Set the position for this overlay. If the position is `undefined` the
33795 * overlay is hidden.
33796 * @param {ol.Coordinate|undefined} position The spatial point that the overlay
33797 * is anchored at.
33798 * @observable
33799 * @api
33800 */
33801ol.Overlay.prototype.setPosition = function(position) {
33802 this.set(ol.Overlay.Property_.POSITION, position);
33803};
33804
33805
33806/**
33807 * Pan the map so that the overlay is entirely visible in the current viewport
33808 * (if necessary).
33809 * @private
33810 */
33811ol.Overlay.prototype.panIntoView_ = function() {
33812 var map = this.getMap();
33813
33814 if (!map || !map.getTargetElement()) {
33815 return;
33816 }
33817
33818 var mapRect = this.getRect_(map.getTargetElement(), map.getSize());
33819 var element = /** @type {!Element} */ (this.getElement());
33820 var overlayRect = this.getRect_(element,
33821 [ol.dom.outerWidth(element), ol.dom.outerHeight(element)]);
33822
33823 var margin = this.autoPanMargin_;
33824 if (!ol.extent.containsExtent(mapRect, overlayRect)) {
33825 // the overlay is not completely inside the viewport, so pan the map
33826 var offsetLeft = overlayRect[0] - mapRect[0];
33827 var offsetRight = mapRect[2] - overlayRect[2];
33828 var offsetTop = overlayRect[1] - mapRect[1];
33829 var offsetBottom = mapRect[3] - overlayRect[3];
33830
33831 var delta = [0, 0];
33832 if (offsetLeft < 0) {
33833 // move map to the left
33834 delta[0] = offsetLeft - margin;
33835 } else if (offsetRight < 0) {
33836 // move map to the right
33837 delta[0] = Math.abs(offsetRight) + margin;
33838 }
33839 if (offsetTop < 0) {
33840 // move map up
33841 delta[1] = offsetTop - margin;
33842 } else if (offsetBottom < 0) {
33843 // move map down
33844 delta[1] = Math.abs(offsetBottom) + margin;
33845 }
33846
33847 if (delta[0] !== 0 || delta[1] !== 0) {
33848 var center = /** @type {ol.Coordinate} */ (map.getView().getCenter());
33849 var centerPx = map.getPixelFromCoordinate(center);
33850 var newCenterPx = [
33851 centerPx[0] + delta[0],
33852 centerPx[1] + delta[1]
33853 ];
33854
33855 map.getView().animate({
33856 center: map.getCoordinateFromPixel(newCenterPx),
33857 duration: this.autoPanAnimation_.duration,
33858 easing: this.autoPanAnimation_.easing
33859 });
33860 }
33861 }
33862};
33863
33864
33865/**
33866 * Get the extent of an element relative to the document
33867 * @param {Element|undefined} element The element.
33868 * @param {ol.Size|undefined} size The size of the element.
33869 * @return {ol.Extent} The extent.
33870 * @private
33871 */
33872ol.Overlay.prototype.getRect_ = function(element, size) {
33873 var box = element.getBoundingClientRect();
33874 var offsetX = box.left + window.pageXOffset;
33875 var offsetY = box.top + window.pageYOffset;
33876 return [
33877 offsetX,
33878 offsetY,
33879 offsetX + size[0],
33880 offsetY + size[1]
33881 ];
33882};
33883
33884
33885/**
33886 * Set the positioning for this overlay.
33887 * @param {ol.OverlayPositioning} positioning how the overlay is
33888 * positioned relative to its point on the map.
33889 * @observable
33890 * @api
33891 */
33892ol.Overlay.prototype.setPositioning = function(positioning) {
33893 this.set(ol.Overlay.Property_.POSITIONING, positioning);
33894};
33895
33896
33897/**
33898 * Modify the visibility of the element.
33899 * @param {boolean} visible Element visibility.
33900 * @protected
33901 */
33902ol.Overlay.prototype.setVisible = function(visible) {
33903 if (this.rendered_.visible !== visible) {
33904 this.element_.style.display = visible ? '' : 'none';
33905 this.rendered_.visible = visible;
33906 }
33907};
33908
33909
33910/**
33911 * Update pixel position.
33912 * @protected
33913 */
33914ol.Overlay.prototype.updatePixelPosition = function() {
33915 var map = this.getMap();
33916 var position = this.getPosition();
33917 if (!map || !map.isRendered() || !position) {
33918 this.setVisible(false);
33919 return;
33920 }
33921
33922 var pixel = map.getPixelFromCoordinate(position);
33923 var mapSize = map.getSize();
33924 this.updateRenderedPosition(pixel, mapSize);
33925};
33926
33927
33928/**
33929 * @param {ol.Pixel} pixel The pixel location.
33930 * @param {ol.Size|undefined} mapSize The map size.
33931 * @protected
33932 */
33933ol.Overlay.prototype.updateRenderedPosition = function(pixel, mapSize) {
33934 var style = this.element_.style;
33935 var offset = this.getOffset();
33936
33937 var positioning = this.getPositioning();
33938
33939 this.setVisible(true);
33940
33941 var offsetX = offset[0];
33942 var offsetY = offset[1];
33943 if (positioning == ol.OverlayPositioning.BOTTOM_RIGHT ||
33944 positioning == ol.OverlayPositioning.CENTER_RIGHT ||
33945 positioning == ol.OverlayPositioning.TOP_RIGHT) {
33946 if (this.rendered_.left_ !== '') {
33947 this.rendered_.left_ = style.left = '';
33948 }
33949 var right = (mapSize[0] - pixel[0] - offsetX) + 'px';
33950 if (this.rendered_.right_ != right) {
33951 this.rendered_.right_ = style.right = right;
33952 }
33953 } else {
33954 if (this.rendered_.right_ !== '') {
33955 this.rendered_.right_ = style.right = '';
33956 }
33957 if (positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
33958 positioning == ol.OverlayPositioning.CENTER_CENTER ||
33959 positioning == ol.OverlayPositioning.TOP_CENTER) {
33960 offsetX -= this.element_.offsetWidth / 2;
33961 }
33962 var left = (pixel[0] + offsetX) + 'px';
33963 if (this.rendered_.left_ != left) {
33964 this.rendered_.left_ = style.left = left;
33965 }
33966 }
33967 if (positioning == ol.OverlayPositioning.BOTTOM_LEFT ||
33968 positioning == ol.OverlayPositioning.BOTTOM_CENTER ||
33969 positioning == ol.OverlayPositioning.BOTTOM_RIGHT) {
33970 if (this.rendered_.top_ !== '') {
33971 this.rendered_.top_ = style.top = '';
33972 }
33973 var bottom = (mapSize[1] - pixel[1] - offsetY) + 'px';
33974 if (this.rendered_.bottom_ != bottom) {
33975 this.rendered_.bottom_ = style.bottom = bottom;
33976 }
33977 } else {
33978 if (this.rendered_.bottom_ !== '') {
33979 this.rendered_.bottom_ = style.bottom = '';
33980 }
33981 if (positioning == ol.OverlayPositioning.CENTER_LEFT ||
33982 positioning == ol.OverlayPositioning.CENTER_CENTER ||
33983 positioning == ol.OverlayPositioning.CENTER_RIGHT) {
33984 offsetY -= this.element_.offsetHeight / 2;
33985 }
33986 var top = (pixel[1] + offsetY) + 'px';
33987 if (this.rendered_.top_ != top) {
33988 this.rendered_.top_ = style.top = top;
33989 }
33990 }
33991};
33992
33993
33994/**
33995 * @enum {string}
33996 * @private
33997 */
33998ol.Overlay.Property_ = {
33999 ELEMENT: 'element',
34000 MAP: 'map',
34001 OFFSET: 'offset',
34002 POSITION: 'position',
34003 POSITIONING: 'positioning'
34004};
34005
34006goog.provide('ol.control.OverviewMap');
34007
34008goog.require('ol');
34009goog.require('ol.Collection');
34010goog.require('ol.Map');
34011goog.require('ol.MapEventType');
34012goog.require('ol.MapProperty');
34013goog.require('ol.Object');
34014goog.require('ol.ObjectEventType');
34015goog.require('ol.Overlay');
34016goog.require('ol.OverlayPositioning');
34017goog.require('ol.ViewProperty');
34018goog.require('ol.control.Control');
34019goog.require('ol.coordinate');
34020goog.require('ol.css');
34021goog.require('ol.dom');
34022goog.require('ol.events');
34023goog.require('ol.events.EventType');
34024goog.require('ol.extent');
34025
34026
34027/**
34028 * Create a new control with a map acting as an overview map for an other
34029 * defined map.
34030 * @constructor
34031 * @extends {ol.control.Control}
34032 * @param {olx.control.OverviewMapOptions=} opt_options OverviewMap options.
34033 * @api
34034 */
34035ol.control.OverviewMap = function(opt_options) {
34036
34037 var options = opt_options ? opt_options : {};
34038
34039 /**
34040 * @type {boolean}
34041 * @private
34042 */
34043 this.collapsed_ = options.collapsed !== undefined ? options.collapsed : true;
34044
34045 /**
34046 * @private
34047 * @type {boolean}
34048 */
34049 this.collapsible_ = options.collapsible !== undefined ?
34050 options.collapsible : true;
34051
34052 if (!this.collapsible_) {
34053 this.collapsed_ = false;
34054 }
34055
34056 var className = options.className !== undefined ? options.className : 'ol-overviewmap';
34057
34058 var tipLabel = options.tipLabel !== undefined ? options.tipLabel : 'Overview map';
34059
34060 var collapseLabel = options.collapseLabel !== undefined ? options.collapseLabel : '\u00AB';
34061
34062 if (typeof collapseLabel === 'string') {
34063 /**
34064 * @private
34065 * @type {Node}
34066 */
34067 this.collapseLabel_ = document.createElement('span');
34068 this.collapseLabel_.textContent = collapseLabel;
34069 } else {
34070 this.collapseLabel_ = collapseLabel;
34071 }
34072
34073 var label = options.label !== undefined ? options.label : '\u00BB';
34074
34075
34076 if (typeof label === 'string') {
34077 /**
34078 * @private
34079 * @type {Node}
34080 */
34081 this.label_ = document.createElement('span');
34082 this.label_.textContent = label;
34083 } else {
34084 this.label_ = label;
34085 }
34086
34087 var activeLabel = (this.collapsible_ && !this.collapsed_) ?
34088 this.collapseLabel_ : this.label_;
34089 var button = document.createElement('button');
34090 button.setAttribute('type', 'button');
34091 button.title = tipLabel;
34092 button.appendChild(activeLabel);
34093
34094 ol.events.listen(button, ol.events.EventType.CLICK,
34095 this.handleClick_, this);
34096
34097 /**
34098 * @type {Element}
34099 * @private
34100 */
34101 this.ovmapDiv_ = document.createElement('DIV');
34102 this.ovmapDiv_.className = 'ol-overviewmap-map';
34103
34104 /**
34105 * @type {ol.Map}
34106 * @private
34107 */
34108 this.ovmap_ = new ol.Map({
34109 controls: new ol.Collection(),
34110 interactions: new ol.Collection(),
34111 view: options.view
34112 });
34113 var ovmap = this.ovmap_;
34114
34115 if (options.layers) {
34116 options.layers.forEach(
34117 /**
34118 * @param {ol.layer.Layer} layer Layer.
34119 */
34120 function(layer) {
34121 ovmap.addLayer(layer);
34122 }, this);
34123 }
34124
34125 var box = document.createElement('DIV');
34126 box.className = 'ol-overviewmap-box';
34127 box.style.boxSizing = 'border-box';
34128
34129 /**
34130 * @type {ol.Overlay}
34131 * @private
34132 */
34133 this.boxOverlay_ = new ol.Overlay({
34134 position: [0, 0],
34135 positioning: ol.OverlayPositioning.BOTTOM_LEFT,
34136 element: box
34137 });
34138 this.ovmap_.addOverlay(this.boxOverlay_);
34139
34140 var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
34141 ol.css.CLASS_CONTROL +
34142 (this.collapsed_ && this.collapsible_ ? ' ol-collapsed' : '') +
34143 (this.collapsible_ ? '' : ' ol-uncollapsible');
34144 var element = document.createElement('div');
34145 element.className = cssClasses;
34146 element.appendChild(this.ovmapDiv_);
34147 element.appendChild(button);
34148
34149 var render = options.render ? options.render : ol.control.OverviewMap.render;
34150
34151 ol.control.Control.call(this, {
34152 element: element,
34153 render: render,
34154 target: options.target
34155 });
34156
34157 /* Interactive map */
34158
34159 var scope = this;
34160
34161 var overlay = this.boxOverlay_;
34162 var overlayBox = this.boxOverlay_.getElement();
34163
34164 /* Functions definition */
34165
34166 var computeDesiredMousePosition = function(mousePosition) {
34167 return {
34168 clientX: mousePosition.clientX - (overlayBox.offsetWidth / 2),
34169 clientY: mousePosition.clientY + (overlayBox.offsetHeight / 2)
34170 };
34171 };
34172
34173 var move = function(event) {
34174 var coordinates = ovmap.getEventCoordinate(computeDesiredMousePosition(event));
34175
34176 overlay.setPosition(coordinates);
34177 };
34178
34179 var endMoving = function(event) {
34180 var coordinates = ovmap.getEventCoordinate(event);
34181
34182 scope.getMap().getView().setCenter(coordinates);
34183
34184 window.removeEventListener('mousemove', move);
34185 window.removeEventListener('mouseup', endMoving);
34186 };
34187
34188 /* Binding */
34189
34190 overlayBox.addEventListener('mousedown', function() {
34191 window.addEventListener('mousemove', move);
34192 window.addEventListener('mouseup', endMoving);
34193 });
34194};
34195ol.inherits(ol.control.OverviewMap, ol.control.Control);
34196
34197
34198/**
34199 * @inheritDoc
34200 * @api
34201 */
34202ol.control.OverviewMap.prototype.setMap = function(map) {
34203 var oldMap = this.getMap();
34204 if (map === oldMap) {
34205 return;
34206 }
34207 if (oldMap) {
34208 var oldView = oldMap.getView();
34209 if (oldView) {
34210 this.unbindView_(oldView);
34211 }
34212 this.ovmap_.setTarget(null);
34213 }
34214 ol.control.Control.prototype.setMap.call(this, map);
34215
34216 if (map) {
34217 this.ovmap_.setTarget(this.ovmapDiv_);
34218 this.listenerKeys.push(ol.events.listen(
34219 map, ol.ObjectEventType.PROPERTYCHANGE,
34220 this.handleMapPropertyChange_, this));
34221
34222 // TODO: to really support map switching, this would need to be reworked
34223 if (this.ovmap_.getLayers().getLength() === 0) {
34224 this.ovmap_.setLayerGroup(map.getLayerGroup());
34225 }
34226
34227 var view = map.getView();
34228 if (view) {
34229 this.bindView_(view);
34230 if (view.isDef()) {
34231 this.ovmap_.updateSize();
34232 this.resetExtent_();
34233 }
34234 }
34235 }
34236};
34237
34238
34239/**
34240 * Handle map property changes. This only deals with changes to the map's view.
34241 * @param {ol.Object.Event} event The propertychange event.
34242 * @private
34243 */
34244ol.control.OverviewMap.prototype.handleMapPropertyChange_ = function(event) {
34245 if (event.key === ol.MapProperty.VIEW) {
34246 var oldView = /** @type {ol.View} */ (event.oldValue);
34247 if (oldView) {
34248 this.unbindView_(oldView);
34249 }
34250 var newView = this.getMap().getView();
34251 this.bindView_(newView);
34252 }
34253};
34254
34255
34256/**
34257 * Register listeners for view property changes.
34258 * @param {ol.View} view The view.
34259 * @private
34260 */
34261ol.control.OverviewMap.prototype.bindView_ = function(view) {
34262 ol.events.listen(view,
34263 ol.Object.getChangeEventType(ol.ViewProperty.ROTATION),
34264 this.handleRotationChanged_, this);
34265};
34266
34267
34268/**
34269 * Unregister listeners for view property changes.
34270 * @param {ol.View} view The view.
34271 * @private
34272 */
34273ol.control.OverviewMap.prototype.unbindView_ = function(view) {
34274 ol.events.unlisten(view,
34275 ol.Object.getChangeEventType(ol.ViewProperty.ROTATION),
34276 this.handleRotationChanged_, this);
34277};
34278
34279
34280/**
34281 * Handle rotation changes to the main map.
34282 * TODO: This should rotate the extent rectrangle instead of the
34283 * overview map's view.
34284 * @private
34285 */
34286ol.control.OverviewMap.prototype.handleRotationChanged_ = function() {
34287 this.ovmap_.getView().setRotation(this.getMap().getView().getRotation());
34288};
34289
34290
34291/**
34292 * Update the overview map element.
34293 * @param {ol.MapEvent} mapEvent Map event.
34294 * @this {ol.control.OverviewMap}
34295 * @api
34296 */
34297ol.control.OverviewMap.render = function(mapEvent) {
34298 this.validateExtent_();
34299 this.updateBox_();
34300};
34301
34302
34303/**
34304 * Reset the overview map extent if the box size (width or
34305 * height) is less than the size of the overview map size times minRatio
34306 * or is greater than the size of the overview size times maxRatio.
34307 *
34308 * If the map extent was not reset, the box size can fits in the defined
34309 * ratio sizes. This method then checks if is contained inside the overview
34310 * map current extent. If not, recenter the overview map to the current
34311 * main map center location.
34312 * @private
34313 */
34314ol.control.OverviewMap.prototype.validateExtent_ = function() {
34315 var map = this.getMap();
34316 var ovmap = this.ovmap_;
34317
34318 if (!map.isRendered() || !ovmap.isRendered()) {
34319 return;
34320 }
34321
34322 var mapSize = /** @type {ol.Size} */ (map.getSize());
34323
34324 var view = map.getView();
34325 var extent = view.calculateExtent(mapSize);
34326
34327 var ovmapSize = /** @type {ol.Size} */ (ovmap.getSize());
34328
34329 var ovview = ovmap.getView();
34330 var ovextent = ovview.calculateExtent(ovmapSize);
34331
34332 var topLeftPixel =
34333 ovmap.getPixelFromCoordinate(ol.extent.getTopLeft(extent));
34334 var bottomRightPixel =
34335 ovmap.getPixelFromCoordinate(ol.extent.getBottomRight(extent));
34336
34337 var boxWidth = Math.abs(topLeftPixel[0] - bottomRightPixel[0]);
34338 var boxHeight = Math.abs(topLeftPixel[1] - bottomRightPixel[1]);
34339
34340 var ovmapWidth = ovmapSize[0];
34341 var ovmapHeight = ovmapSize[1];
34342
34343 if (boxWidth < ovmapWidth * ol.OVERVIEWMAP_MIN_RATIO ||
34344 boxHeight < ovmapHeight * ol.OVERVIEWMAP_MIN_RATIO ||
34345 boxWidth > ovmapWidth * ol.OVERVIEWMAP_MAX_RATIO ||
34346 boxHeight > ovmapHeight * ol.OVERVIEWMAP_MAX_RATIO) {
34347 this.resetExtent_();
34348 } else if (!ol.extent.containsExtent(ovextent, extent)) {
34349 this.recenter_();
34350 }
34351};
34352
34353
34354/**
34355 * Reset the overview map extent to half calculated min and max ratio times
34356 * the extent of the main map.
34357 * @private
34358 */
34359ol.control.OverviewMap.prototype.resetExtent_ = function() {
34360 if (ol.OVERVIEWMAP_MAX_RATIO === 0 || ol.OVERVIEWMAP_MIN_RATIO === 0) {
34361 return;
34362 }
34363
34364 var map = this.getMap();
34365 var ovmap = this.ovmap_;
34366
34367 var mapSize = /** @type {ol.Size} */ (map.getSize());
34368
34369 var view = map.getView();
34370 var extent = view.calculateExtent(mapSize);
34371
34372 var ovview = ovmap.getView();
34373
34374 // get how many times the current map overview could hold different
34375 // box sizes using the min and max ratio, pick the step in the middle used
34376 // to calculate the extent from the main map to set it to the overview map,
34377 var steps = Math.log(
34378 ol.OVERVIEWMAP_MAX_RATIO / ol.OVERVIEWMAP_MIN_RATIO) / Math.LN2;
34379 var ratio = 1 / (Math.pow(2, steps / 2) * ol.OVERVIEWMAP_MIN_RATIO);
34380 ol.extent.scaleFromCenter(extent, ratio);
34381 ovview.fit(extent);
34382};
34383
34384
34385/**
34386 * Set the center of the overview map to the map center without changing its
34387 * resolution.
34388 * @private
34389 */
34390ol.control.OverviewMap.prototype.recenter_ = function() {
34391 var map = this.getMap();
34392 var ovmap = this.ovmap_;
34393
34394 var view = map.getView();
34395
34396 var ovview = ovmap.getView();
34397
34398 ovview.setCenter(view.getCenter());
34399};
34400
34401
34402/**
34403 * Update the box using the main map extent
34404 * @private
34405 */
34406ol.control.OverviewMap.prototype.updateBox_ = function() {
34407 var map = this.getMap();
34408 var ovmap = this.ovmap_;
34409
34410 if (!map.isRendered() || !ovmap.isRendered()) {
34411 return;
34412 }
34413
34414 var mapSize = /** @type {ol.Size} */ (map.getSize());
34415
34416 var view = map.getView();
34417
34418 var ovview = ovmap.getView();
34419
34420 var rotation = view.getRotation();
34421
34422 var overlay = this.boxOverlay_;
34423 var box = this.boxOverlay_.getElement();
34424 var extent = view.calculateExtent(mapSize);
34425 var ovresolution = ovview.getResolution();
34426 var bottomLeft = ol.extent.getBottomLeft(extent);
34427 var topRight = ol.extent.getTopRight(extent);
34428
34429 // set position using bottom left coordinates
34430 var rotateBottomLeft = this.calculateCoordinateRotate_(rotation, bottomLeft);
34431 overlay.setPosition(rotateBottomLeft);
34432
34433 // set box size calculated from map extent size and overview map resolution
34434 if (box) {
34435 box.style.width = Math.abs((bottomLeft[0] - topRight[0]) / ovresolution) + 'px';
34436 box.style.height = Math.abs((topRight[1] - bottomLeft[1]) / ovresolution) + 'px';
34437 }
34438};
34439
34440
34441/**
34442 * @param {number} rotation Target rotation.
34443 * @param {ol.Coordinate} coordinate Coordinate.
34444 * @return {ol.Coordinate|undefined} Coordinate for rotation and center anchor.
34445 * @private
34446 */
34447ol.control.OverviewMap.prototype.calculateCoordinateRotate_ = function(
34448 rotation, coordinate) {
34449 var coordinateRotate;
34450
34451 var map = this.getMap();
34452 var view = map.getView();
34453
34454 var currentCenter = view.getCenter();
34455
34456 if (currentCenter) {
34457 coordinateRotate = [
34458 coordinate[0] - currentCenter[0],
34459 coordinate[1] - currentCenter[1]
34460 ];
34461 ol.coordinate.rotate(coordinateRotate, rotation);
34462 ol.coordinate.add(coordinateRotate, currentCenter);
34463 }
34464 return coordinateRotate;
34465};
34466
34467
34468/**
34469 * @param {Event} event The event to handle
34470 * @private
34471 */
34472ol.control.OverviewMap.prototype.handleClick_ = function(event) {
34473 event.preventDefault();
34474 this.handleToggle_();
34475};
34476
34477
34478/**
34479 * @private
34480 */
34481ol.control.OverviewMap.prototype.handleToggle_ = function() {
34482 this.element.classList.toggle('ol-collapsed');
34483 if (this.collapsed_) {
34484 ol.dom.replaceNode(this.collapseLabel_, this.label_);
34485 } else {
34486 ol.dom.replaceNode(this.label_, this.collapseLabel_);
34487 }
34488 this.collapsed_ = !this.collapsed_;
34489
34490 // manage overview map if it had not been rendered before and control
34491 // is expanded
34492 var ovmap = this.ovmap_;
34493 if (!this.collapsed_ && !ovmap.isRendered()) {
34494 ovmap.updateSize();
34495 this.resetExtent_();
34496 ol.events.listenOnce(ovmap, ol.MapEventType.POSTRENDER,
34497 function(event) {
34498 this.updateBox_();
34499 },
34500 this);
34501 }
34502};
34503
34504
34505/**
34506 * Return `true` if the overview map is collapsible, `false` otherwise.
34507 * @return {boolean} True if the widget is collapsible.
34508 * @api
34509 */
34510ol.control.OverviewMap.prototype.getCollapsible = function() {
34511 return this.collapsible_;
34512};
34513
34514
34515/**
34516 * Set whether the overview map should be collapsible.
34517 * @param {boolean} collapsible True if the widget is collapsible.
34518 * @api
34519 */
34520ol.control.OverviewMap.prototype.setCollapsible = function(collapsible) {
34521 if (this.collapsible_ === collapsible) {
34522 return;
34523 }
34524 this.collapsible_ = collapsible;
34525 this.element.classList.toggle('ol-uncollapsible');
34526 if (!collapsible && this.collapsed_) {
34527 this.handleToggle_();
34528 }
34529};
34530
34531
34532/**
34533 * Collapse or expand the overview map according to the passed parameter. Will
34534 * not do anything if the overview map isn't collapsible or if the current
34535 * collapsed state is already the one requested.
34536 * @param {boolean} collapsed True if the widget is collapsed.
34537 * @api
34538 */
34539ol.control.OverviewMap.prototype.setCollapsed = function(collapsed) {
34540 if (!this.collapsible_ || this.collapsed_ === collapsed) {
34541 return;
34542 }
34543 this.handleToggle_();
34544};
34545
34546
34547/**
34548 * Determine if the overview map is collapsed.
34549 * @return {boolean} The overview map is collapsed.
34550 * @api
34551 */
34552ol.control.OverviewMap.prototype.getCollapsed = function() {
34553 return this.collapsed_;
34554};
34555
34556
34557/**
34558 * Return the overview map.
34559 * @return {ol.Map} Overview map.
34560 * @api
34561 */
34562ol.control.OverviewMap.prototype.getOverviewMap = function() {
34563 return this.ovmap_;
34564};
34565
34566goog.provide('ol.control.ScaleLineUnits');
34567
34568/**
34569 * Units for the scale line. Supported values are `'degrees'`, `'imperial'`,
34570 * `'nautical'`, `'metric'`, `'us'`.
34571 * @enum {string}
34572 */
34573ol.control.ScaleLineUnits = {
34574 DEGREES: 'degrees',
34575 IMPERIAL: 'imperial',
34576 NAUTICAL: 'nautical',
34577 METRIC: 'metric',
34578 US: 'us'
34579};
34580
34581goog.provide('ol.control.ScaleLine');
34582
34583goog.require('ol');
34584goog.require('ol.Object');
34585goog.require('ol.asserts');
34586goog.require('ol.control.Control');
34587goog.require('ol.control.ScaleLineUnits');
34588goog.require('ol.css');
34589goog.require('ol.events');
34590goog.require('ol.proj');
34591goog.require('ol.proj.Units');
34592
34593
34594/**
34595 * @classdesc
34596 * A control displaying rough y-axis distances, calculated for the center of the
34597 * viewport. For conformal projections (e.g. EPSG:3857, the default view
34598 * projection in OpenLayers), the scale is valid for all directions.
34599 * No scale line will be shown when the y-axis distance of a pixel at the
34600 * viewport center cannot be calculated in the view projection.
34601 * By default the scale line will show in the bottom left portion of the map,
34602 * but this can be changed by using the css selector `.ol-scale-line`.
34603 *
34604 * @constructor
34605 * @extends {ol.control.Control}
34606 * @param {olx.control.ScaleLineOptions=} opt_options Scale line options.
34607 * @api
34608 */
34609ol.control.ScaleLine = function(opt_options) {
34610
34611 var options = opt_options ? opt_options : {};
34612
34613 var className = options.className !== undefined ? options.className : 'ol-scale-line';
34614
34615 /**
34616 * @private
34617 * @type {Element}
34618 */
34619 this.innerElement_ = document.createElement('DIV');
34620 this.innerElement_.className = className + '-inner';
34621
34622 /**
34623 * @private
34624 * @type {Element}
34625 */
34626 this.element_ = document.createElement('DIV');
34627 this.element_.className = className + ' ' + ol.css.CLASS_UNSELECTABLE;
34628 this.element_.appendChild(this.innerElement_);
34629
34630 /**
34631 * @private
34632 * @type {?olx.ViewState}
34633 */
34634 this.viewState_ = null;
34635
34636 /**
34637 * @private
34638 * @type {number}
34639 */
34640 this.minWidth_ = options.minWidth !== undefined ? options.minWidth : 64;
34641
34642 /**
34643 * @private
34644 * @type {boolean}
34645 */
34646 this.renderedVisible_ = false;
34647
34648 /**
34649 * @private
34650 * @type {number|undefined}
34651 */
34652 this.renderedWidth_ = undefined;
34653
34654 /**
34655 * @private
34656 * @type {string}
34657 */
34658 this.renderedHTML_ = '';
34659
34660 var render = options.render ? options.render : ol.control.ScaleLine.render;
34661
34662 ol.control.Control.call(this, {
34663 element: this.element_,
34664 render: render,
34665 target: options.target
34666 });
34667
34668 ol.events.listen(
34669 this, ol.Object.getChangeEventType(ol.control.ScaleLine.Property_.UNITS),
34670 this.handleUnitsChanged_, this);
34671
34672 this.setUnits(/** @type {ol.control.ScaleLineUnits} */ (options.units) ||
34673 ol.control.ScaleLineUnits.METRIC);
34674
34675};
34676ol.inherits(ol.control.ScaleLine, ol.control.Control);
34677
34678
34679/**
34680 * @const
34681 * @type {Array.<number>}
34682 */
34683ol.control.ScaleLine.LEADING_DIGITS = [1, 2, 5];
34684
34685
34686/**
34687 * Return the units to use in the scale line.
34688 * @return {ol.control.ScaleLineUnits|undefined} The units to use in the scale
34689 * line.
34690 * @observable
34691 * @api
34692 */
34693ol.control.ScaleLine.prototype.getUnits = function() {
34694 return /** @type {ol.control.ScaleLineUnits|undefined} */ (
34695 this.get(ol.control.ScaleLine.Property_.UNITS));
34696};
34697
34698
34699/**
34700 * Update the scale line element.
34701 * @param {ol.MapEvent} mapEvent Map event.
34702 * @this {ol.control.ScaleLine}
34703 * @api
34704 */
34705ol.control.ScaleLine.render = function(mapEvent) {
34706 var frameState = mapEvent.frameState;
34707 if (!frameState) {
34708 this.viewState_ = null;
34709 } else {
34710 this.viewState_ = frameState.viewState;
34711 }
34712 this.updateElement_();
34713};
34714
34715
34716/**
34717 * @private
34718 */
34719ol.control.ScaleLine.prototype.handleUnitsChanged_ = function() {
34720 this.updateElement_();
34721};
34722
34723
34724/**
34725 * Set the units to use in the scale line.
34726 * @param {ol.control.ScaleLineUnits} units The units to use in the scale line.
34727 * @observable
34728 * @api
34729 */
34730ol.control.ScaleLine.prototype.setUnits = function(units) {
34731 this.set(ol.control.ScaleLine.Property_.UNITS, units);
34732};
34733
34734
34735/**
34736 * @private
34737 */
34738ol.control.ScaleLine.prototype.updateElement_ = function() {
34739 var viewState = this.viewState_;
34740
34741 if (!viewState) {
34742 if (this.renderedVisible_) {
34743 this.element_.style.display = 'none';
34744 this.renderedVisible_ = false;
34745 }
34746 return;
34747 }
34748
34749 var center = viewState.center;
34750 var projection = viewState.projection;
34751 var units = this.getUnits();
34752 var pointResolutionUnits = units == ol.control.ScaleLineUnits.DEGREES ?
34753 ol.proj.Units.DEGREES :
34754 ol.proj.Units.METERS;
34755 var pointResolution =
34756 ol.proj.getPointResolution(projection, viewState.resolution, center, pointResolutionUnits);
34757
34758 var nominalCount = this.minWidth_ * pointResolution;
34759 var suffix = '';
34760 if (units == ol.control.ScaleLineUnits.DEGREES) {
34761 var metersPerDegree = ol.proj.METERS_PER_UNIT[ol.proj.Units.DEGREES];
34762 if (projection.getUnits() == ol.proj.Units.DEGREES) {
34763 nominalCount *= metersPerDegree;
34764 } else {
34765 pointResolution /= metersPerDegree;
34766 }
34767 if (nominalCount < metersPerDegree / 60) {
34768 suffix = '\u2033'; // seconds
34769 pointResolution *= 3600;
34770 } else if (nominalCount < metersPerDegree) {
34771 suffix = '\u2032'; // minutes
34772 pointResolution *= 60;
34773 } else {
34774 suffix = '\u00b0'; // degrees
34775 }
34776 } else if (units == ol.control.ScaleLineUnits.IMPERIAL) {
34777 if (nominalCount < 0.9144) {
34778 suffix = 'in';
34779 pointResolution /= 0.0254;
34780 } else if (nominalCount < 1609.344) {
34781 suffix = 'ft';
34782 pointResolution /= 0.3048;
34783 } else {
34784 suffix = 'mi';
34785 pointResolution /= 1609.344;
34786 }
34787 } else if (units == ol.control.ScaleLineUnits.NAUTICAL) {
34788 pointResolution /= 1852;
34789 suffix = 'nm';
34790 } else if (units == ol.control.ScaleLineUnits.METRIC) {
34791 if (nominalCount < 0.001) {
34792 suffix = 'μm';
34793 pointResolution *= 1000000;
34794 } else if (nominalCount < 1) {
34795 suffix = 'mm';
34796 pointResolution *= 1000;
34797 } else if (nominalCount < 1000) {
34798 suffix = 'm';
34799 } else {
34800 suffix = 'km';
34801 pointResolution /= 1000;
34802 }
34803 } else if (units == ol.control.ScaleLineUnits.US) {
34804 if (nominalCount < 0.9144) {
34805 suffix = 'in';
34806 pointResolution *= 39.37;
34807 } else if (nominalCount < 1609.344) {
34808 suffix = 'ft';
34809 pointResolution /= 0.30480061;
34810 } else {
34811 suffix = 'mi';
34812 pointResolution /= 1609.3472;
34813 }
34814 } else {
34815 ol.asserts.assert(false, 33); // Invalid units
34816 }
34817
34818 var i = 3 * Math.floor(
34819 Math.log(this.minWidth_ * pointResolution) / Math.log(10));
34820 var count, width;
34821 while (true) {
34822 count = ol.control.ScaleLine.LEADING_DIGITS[((i % 3) + 3) % 3] *
34823 Math.pow(10, Math.floor(i / 3));
34824 width = Math.round(count / pointResolution);
34825 if (isNaN(width)) {
34826 this.element_.style.display = 'none';
34827 this.renderedVisible_ = false;
34828 return;
34829 } else if (width >= this.minWidth_) {
34830 break;
34831 }
34832 ++i;
34833 }
34834
34835 var html = count + ' ' + suffix;
34836 if (this.renderedHTML_ != html) {
34837 this.innerElement_.innerHTML = html;
34838 this.renderedHTML_ = html;
34839 }
34840
34841 if (this.renderedWidth_ != width) {
34842 this.innerElement_.style.width = width + 'px';
34843 this.renderedWidth_ = width;
34844 }
34845
34846 if (!this.renderedVisible_) {
34847 this.element_.style.display = '';
34848 this.renderedVisible_ = true;
34849 }
34850
34851};
34852
34853
34854/**
34855 * @enum {string}
34856 * @private
34857 */
34858ol.control.ScaleLine.Property_ = {
34859 UNITS: 'units'
34860};
34861
34862// FIXME should possibly show tooltip when dragging?
34863
34864goog.provide('ol.control.ZoomSlider');
34865
34866goog.require('ol');
34867goog.require('ol.ViewHint');
34868goog.require('ol.control.Control');
34869goog.require('ol.css');
34870goog.require('ol.easing');
34871goog.require('ol.events');
34872goog.require('ol.events.Event');
34873goog.require('ol.events.EventType');
34874goog.require('ol.math');
34875goog.require('ol.pointer.EventType');
34876goog.require('ol.pointer.PointerEventHandler');
34877
34878
34879/**
34880 * @classdesc
34881 * A slider type of control for zooming.
34882 *
34883 * Example:
34884 *
34885 * map.addControl(new ol.control.ZoomSlider());
34886 *
34887 * @constructor
34888 * @extends {ol.control.Control}
34889 * @param {olx.control.ZoomSliderOptions=} opt_options Zoom slider options.
34890 * @api
34891 */
34892ol.control.ZoomSlider = function(opt_options) {
34893
34894 var options = opt_options ? opt_options : {};
34895
34896 /**
34897 * Will hold the current resolution of the view.
34898 *
34899 * @type {number|undefined}
34900 * @private
34901 */
34902 this.currentResolution_ = undefined;
34903
34904 /**
34905 * The direction of the slider. Will be determined from actual display of the
34906 * container and defaults to ol.control.ZoomSlider.Direction_.VERTICAL.
34907 *
34908 * @type {ol.control.ZoomSlider.Direction_}
34909 * @private
34910 */
34911 this.direction_ = ol.control.ZoomSlider.Direction_.VERTICAL;
34912
34913 /**
34914 * @type {boolean}
34915 * @private
34916 */
34917 this.dragging_;
34918
34919 /**
34920 * @type {number}
34921 * @private
34922 */
34923 this.heightLimit_ = 0;
34924
34925 /**
34926 * @type {number}
34927 * @private
34928 */
34929 this.widthLimit_ = 0;
34930
34931 /**
34932 * @type {number|undefined}
34933 * @private
34934 */
34935 this.previousX_;
34936
34937 /**
34938 * @type {number|undefined}
34939 * @private
34940 */
34941 this.previousY_;
34942
34943 /**
34944 * The calculated thumb size (border box plus margins). Set when initSlider_
34945 * is called.
34946 * @type {ol.Size}
34947 * @private
34948 */
34949 this.thumbSize_ = null;
34950
34951 /**
34952 * Whether the slider is initialized.
34953 * @type {boolean}
34954 * @private
34955 */
34956 this.sliderInitialized_ = false;
34957
34958 /**
34959 * @type {number}
34960 * @private
34961 */
34962 this.duration_ = options.duration !== undefined ? options.duration : 200;
34963
34964 var className = options.className !== undefined ? options.className : 'ol-zoomslider';
34965 var thumbElement = document.createElement('button');
34966 thumbElement.setAttribute('type', 'button');
34967 thumbElement.className = className + '-thumb ' + ol.css.CLASS_UNSELECTABLE;
34968 var containerElement = document.createElement('div');
34969 containerElement.className = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' + ol.css.CLASS_CONTROL;
34970 containerElement.appendChild(thumbElement);
34971 /**
34972 * @type {ol.pointer.PointerEventHandler}
34973 * @private
34974 */
34975 this.dragger_ = new ol.pointer.PointerEventHandler(containerElement);
34976
34977 ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERDOWN,
34978 this.handleDraggerStart_, this);
34979 ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERMOVE,
34980 this.handleDraggerDrag_, this);
34981 ol.events.listen(this.dragger_, ol.pointer.EventType.POINTERUP,
34982 this.handleDraggerEnd_, this);
34983
34984 ol.events.listen(containerElement, ol.events.EventType.CLICK,
34985 this.handleContainerClick_, this);
34986 ol.events.listen(thumbElement, ol.events.EventType.CLICK,
34987 ol.events.Event.stopPropagation);
34988
34989 var render = options.render ? options.render : ol.control.ZoomSlider.render;
34990
34991 ol.control.Control.call(this, {
34992 element: containerElement,
34993 render: render
34994 });
34995};
34996ol.inherits(ol.control.ZoomSlider, ol.control.Control);
34997
34998
34999/**
35000 * @inheritDoc
35001 */
35002ol.control.ZoomSlider.prototype.disposeInternal = function() {
35003 this.dragger_.dispose();
35004 ol.control.Control.prototype.disposeInternal.call(this);
35005};
35006
35007
35008/**
35009 * The enum for available directions.
35010 *
35011 * @enum {number}
35012 * @private
35013 */
35014ol.control.ZoomSlider.Direction_ = {
35015 VERTICAL: 0,
35016 HORIZONTAL: 1
35017};
35018
35019
35020/**
35021 * @inheritDoc
35022 */
35023ol.control.ZoomSlider.prototype.setMap = function(map) {
35024 ol.control.Control.prototype.setMap.call(this, map);
35025 if (map) {
35026 map.render();
35027 }
35028};
35029
35030
35031/**
35032 * Initializes the slider element. This will determine and set this controls
35033 * direction_ and also constrain the dragging of the thumb to always be within
35034 * the bounds of the container.
35035 *
35036 * @private
35037 */
35038ol.control.ZoomSlider.prototype.initSlider_ = function() {
35039 var container = this.element;
35040 var containerSize = {
35041 width: container.offsetWidth, height: container.offsetHeight
35042 };
35043
35044 var thumb = container.firstElementChild;
35045 var computedStyle = getComputedStyle(thumb);
35046 var thumbWidth = thumb.offsetWidth +
35047 parseFloat(computedStyle['marginRight']) +
35048 parseFloat(computedStyle['marginLeft']);
35049 var thumbHeight = thumb.offsetHeight +
35050 parseFloat(computedStyle['marginTop']) +
35051 parseFloat(computedStyle['marginBottom']);
35052 this.thumbSize_ = [thumbWidth, thumbHeight];
35053
35054 if (containerSize.width > containerSize.height) {
35055 this.direction_ = ol.control.ZoomSlider.Direction_.HORIZONTAL;
35056 this.widthLimit_ = containerSize.width - thumbWidth;
35057 } else {
35058 this.direction_ = ol.control.ZoomSlider.Direction_.VERTICAL;
35059 this.heightLimit_ = containerSize.height - thumbHeight;
35060 }
35061 this.sliderInitialized_ = true;
35062};
35063
35064
35065/**
35066 * Update the zoomslider element.
35067 * @param {ol.MapEvent} mapEvent Map event.
35068 * @this {ol.control.ZoomSlider}
35069 * @api
35070 */
35071ol.control.ZoomSlider.render = function(mapEvent) {
35072 if (!mapEvent.frameState) {
35073 return;
35074 }
35075 if (!this.sliderInitialized_) {
35076 this.initSlider_();
35077 }
35078 var res = mapEvent.frameState.viewState.resolution;
35079 if (res !== this.currentResolution_) {
35080 this.currentResolution_ = res;
35081 this.setThumbPosition_(res);
35082 }
35083};
35084
35085
35086/**
35087 * @param {Event} event The browser event to handle.
35088 * @private
35089 */
35090ol.control.ZoomSlider.prototype.handleContainerClick_ = function(event) {
35091 var view = this.getMap().getView();
35092
35093 var relativePosition = this.getRelativePosition_(
35094 event.offsetX - this.thumbSize_[0] / 2,
35095 event.offsetY - this.thumbSize_[1] / 2);
35096
35097 var resolution = this.getResolutionForPosition_(relativePosition);
35098
35099 view.animate({
35100 resolution: view.constrainResolution(resolution),
35101 duration: this.duration_,
35102 easing: ol.easing.easeOut
35103 });
35104};
35105
35106
35107/**
35108 * Handle dragger start events.
35109 * @param {ol.pointer.PointerEvent} event The drag event.
35110 * @private
35111 */
35112ol.control.ZoomSlider.prototype.handleDraggerStart_ = function(event) {
35113 if (!this.dragging_ && event.originalEvent.target === this.element.firstElementChild) {
35114 this.getMap().getView().setHint(ol.ViewHint.INTERACTING, 1);
35115 this.previousX_ = event.clientX;
35116 this.previousY_ = event.clientY;
35117 this.dragging_ = true;
35118 }
35119};
35120
35121
35122/**
35123 * Handle dragger drag events.
35124 *
35125 * @param {ol.pointer.PointerEvent|Event} event The drag event.
35126 * @private
35127 */
35128ol.control.ZoomSlider.prototype.handleDraggerDrag_ = function(event) {
35129 if (this.dragging_) {
35130 var element = this.element.firstElementChild;
35131 var deltaX = event.clientX - this.previousX_ + parseInt(element.style.left, 10);
35132 var deltaY = event.clientY - this.previousY_ + parseInt(element.style.top, 10);
35133 var relativePosition = this.getRelativePosition_(deltaX, deltaY);
35134 this.currentResolution_ = this.getResolutionForPosition_(relativePosition);
35135 this.getMap().getView().setResolution(this.currentResolution_);
35136 this.setThumbPosition_(this.currentResolution_);
35137 this.previousX_ = event.clientX;
35138 this.previousY_ = event.clientY;
35139 }
35140};
35141
35142
35143/**
35144 * Handle dragger end events.
35145 * @param {ol.pointer.PointerEvent|Event} event The drag event.
35146 * @private
35147 */
35148ol.control.ZoomSlider.prototype.handleDraggerEnd_ = function(event) {
35149 if (this.dragging_) {
35150 var view = this.getMap().getView();
35151 view.setHint(ol.ViewHint.INTERACTING, -1);
35152
35153 view.animate({
35154 resolution: view.constrainResolution(this.currentResolution_),
35155 duration: this.duration_,
35156 easing: ol.easing.easeOut
35157 });
35158
35159 this.dragging_ = false;
35160 this.previousX_ = undefined;
35161 this.previousY_ = undefined;
35162 }
35163};
35164
35165
35166/**
35167 * Positions the thumb inside its container according to the given resolution.
35168 *
35169 * @param {number} res The res.
35170 * @private
35171 */
35172ol.control.ZoomSlider.prototype.setThumbPosition_ = function(res) {
35173 var position = this.getPositionForResolution_(res);
35174 var thumb = this.element.firstElementChild;
35175
35176 if (this.direction_ == ol.control.ZoomSlider.Direction_.HORIZONTAL) {
35177 thumb.style.left = this.widthLimit_ * position + 'px';
35178 } else {
35179 thumb.style.top = this.heightLimit_ * position + 'px';
35180 }
35181};
35182
35183
35184/**
35185 * Calculates the relative position of the thumb given x and y offsets. The
35186 * relative position scales from 0 to 1. The x and y offsets are assumed to be
35187 * in pixel units within the dragger limits.
35188 *
35189 * @param {number} x Pixel position relative to the left of the slider.
35190 * @param {number} y Pixel position relative to the top of the slider.
35191 * @return {number} The relative position of the thumb.
35192 * @private
35193 */
35194ol.control.ZoomSlider.prototype.getRelativePosition_ = function(x, y) {
35195 var amount;
35196 if (this.direction_ === ol.control.ZoomSlider.Direction_.HORIZONTAL) {
35197 amount = x / this.widthLimit_;
35198 } else {
35199 amount = y / this.heightLimit_;
35200 }
35201 return ol.math.clamp(amount, 0, 1);
35202};
35203
35204
35205/**
35206 * Calculates the corresponding resolution of the thumb given its relative
35207 * position (where 0 is the minimum and 1 is the maximum).
35208 *
35209 * @param {number} position The relative position of the thumb.
35210 * @return {number} The corresponding resolution.
35211 * @private
35212 */
35213ol.control.ZoomSlider.prototype.getResolutionForPosition_ = function(position) {
35214 var fn = this.getMap().getView().getResolutionForValueFunction();
35215 return fn(1 - position);
35216};
35217
35218
35219/**
35220 * Determines the relative position of the slider for the given resolution. A
35221 * relative position of 0 corresponds to the minimum view resolution. A
35222 * relative position of 1 corresponds to the maximum view resolution.
35223 *
35224 * @param {number} res The resolution.
35225 * @return {number} The relative position value (between 0 and 1).
35226 * @private
35227 */
35228ol.control.ZoomSlider.prototype.getPositionForResolution_ = function(res) {
35229 var fn = this.getMap().getView().getValueForResolutionFunction();
35230 return 1 - fn(res);
35231};
35232
35233goog.provide('ol.control.ZoomToExtent');
35234
35235goog.require('ol');
35236goog.require('ol.events');
35237goog.require('ol.events.EventType');
35238goog.require('ol.control.Control');
35239goog.require('ol.css');
35240
35241
35242/**
35243 * @classdesc
35244 * A button control which, when pressed, changes the map view to a specific
35245 * extent. To style this control use the css selector `.ol-zoom-extent`.
35246 *
35247 * @constructor
35248 * @extends {ol.control.Control}
35249 * @param {olx.control.ZoomToExtentOptions=} opt_options Options.
35250 * @api
35251 */
35252ol.control.ZoomToExtent = function(opt_options) {
35253 var options = opt_options ? opt_options : {};
35254
35255 /**
35256 * @type {ol.Extent}
35257 * @private
35258 */
35259 this.extent_ = options.extent ? options.extent : null;
35260
35261 var className = options.className !== undefined ? options.className :
35262 'ol-zoom-extent';
35263
35264 var label = options.label !== undefined ? options.label : 'E';
35265 var tipLabel = options.tipLabel !== undefined ?
35266 options.tipLabel : 'Fit to extent';
35267 var button = document.createElement('button');
35268 button.setAttribute('type', 'button');
35269 button.title = tipLabel;
35270 button.appendChild(
35271 typeof label === 'string' ? document.createTextNode(label) : label
35272 );
35273
35274 ol.events.listen(button, ol.events.EventType.CLICK,
35275 this.handleClick_, this);
35276
35277 var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
35278 ol.css.CLASS_CONTROL;
35279 var element = document.createElement('div');
35280 element.className = cssClasses;
35281 element.appendChild(button);
35282
35283 ol.control.Control.call(this, {
35284 element: element,
35285 target: options.target
35286 });
35287};
35288ol.inherits(ol.control.ZoomToExtent, ol.control.Control);
35289
35290
35291/**
35292 * @param {Event} event The event to handle
35293 * @private
35294 */
35295ol.control.ZoomToExtent.prototype.handleClick_ = function(event) {
35296 event.preventDefault();
35297 this.handleZoomToExtent_();
35298};
35299
35300
35301/**
35302 * @private
35303 */
35304ol.control.ZoomToExtent.prototype.handleZoomToExtent_ = function() {
35305 var map = this.getMap();
35306 var view = map.getView();
35307 var extent = !this.extent_ ? view.getProjection().getExtent() : this.extent_;
35308 view.fit(extent);
35309};
35310
35311goog.provide('ol.DeviceOrientation');
35312
35313goog.require('ol.events');
35314goog.require('ol');
35315goog.require('ol.Object');
35316goog.require('ol.has');
35317goog.require('ol.math');
35318
35319
35320/**
35321 * @classdesc
35322 * The ol.DeviceOrientation class provides access to information from
35323 * DeviceOrientation events. See the [HTML 5 DeviceOrientation Specification](
35324 * http://www.w3.org/TR/orientation-event/) for more details.
35325 *
35326 * Many new computers, and especially mobile phones
35327 * and tablets, provide hardware support for device orientation. Web
35328 * developers targeting mobile devices will be especially interested in this
35329 * class.
35330 *
35331 * Device orientation data are relative to a common starting point. For mobile
35332 * devices, the starting point is to lay your phone face up on a table with the
35333 * top of the phone pointing north. This represents the zero state. All
35334 * angles are then relative to this state. For computers, it is the same except
35335 * the screen is open at 90 degrees.
35336 *
35337 * Device orientation is reported as three angles - `alpha`, `beta`, and
35338 * `gamma` - relative to the starting position along the three planar axes X, Y
35339 * and Z. The X axis runs from the left edge to the right edge through the
35340 * middle of the device. Similarly, the Y axis runs from the bottom to the top
35341 * of the device through the middle. The Z axis runs from the back to the front
35342 * through the middle. In the starting position, the X axis points to the
35343 * right, the Y axis points away from you and the Z axis points straight up
35344 * from the device lying flat.
35345 *
35346 * The three angles representing the device orientation are relative to the
35347 * three axes. `alpha` indicates how much the device has been rotated around the
35348 * Z axis, which is commonly interpreted as the compass heading (see note
35349 * below). `beta` indicates how much the device has been rotated around the X
35350 * axis, or how much it is tilted from front to back. `gamma` indicates how
35351 * much the device has been rotated around the Y axis, or how much it is tilted
35352 * from left to right.
35353 *
35354 * For most browsers, the `alpha` value returns the compass heading so if the
35355 * device points north, it will be 0. With Safari on iOS, the 0 value of
35356 * `alpha` is calculated from when device orientation was first requested.
35357 * ol.DeviceOrientation provides the `heading` property which normalizes this
35358 * behavior across all browsers for you.
35359 *
35360 * It is important to note that the HTML 5 DeviceOrientation specification
35361 * indicates that `alpha`, `beta` and `gamma` are in degrees while the
35362 * equivalent properties in ol.DeviceOrientation are in radians for consistency
35363 * with all other uses of angles throughout OpenLayers.
35364 *
35365 * To get notified of device orientation changes, register a listener for the
35366 * generic `change` event on your `ol.DeviceOrientation` instance.
35367 *
35368 * @see {@link http://www.w3.org/TR/orientation-event/}
35369 *
35370 * @constructor
35371 * @extends {ol.Object}
35372 * @param {olx.DeviceOrientationOptions=} opt_options Options.
35373 * @api
35374 */
35375ol.DeviceOrientation = function(opt_options) {
35376
35377 ol.Object.call(this);
35378
35379 var options = opt_options ? opt_options : {};
35380
35381 /**
35382 * @private
35383 * @type {?ol.EventsKey}
35384 */
35385 this.listenerKey_ = null;
35386
35387 ol.events.listen(this,
35388 ol.Object.getChangeEventType(ol.DeviceOrientation.Property_.TRACKING),
35389 this.handleTrackingChanged_, this);
35390
35391 this.setTracking(options.tracking !== undefined ? options.tracking : false);
35392
35393};
35394ol.inherits(ol.DeviceOrientation, ol.Object);
35395
35396
35397/**
35398 * @inheritDoc
35399 */
35400ol.DeviceOrientation.prototype.disposeInternal = function() {
35401 this.setTracking(false);
35402 ol.Object.prototype.disposeInternal.call(this);
35403};
35404
35405
35406/**
35407 * @private
35408 * @param {Event} originalEvent Event.
35409 */
35410ol.DeviceOrientation.prototype.orientationChange_ = function(originalEvent) {
35411 var event = /** @type {DeviceOrientationEvent} */ (originalEvent);
35412 if (event.alpha !== null) {
35413 var alpha = ol.math.toRadians(event.alpha);
35414 this.set(ol.DeviceOrientation.Property_.ALPHA, alpha);
35415 // event.absolute is undefined in iOS.
35416 if (typeof event.absolute === 'boolean' && event.absolute) {
35417 this.set(ol.DeviceOrientation.Property_.HEADING, alpha);
35418 } else if (typeof event.webkitCompassHeading === 'number' &&
35419 event.webkitCompassAccuracy != -1) {
35420 var heading = ol.math.toRadians(event.webkitCompassHeading);
35421 this.set(ol.DeviceOrientation.Property_.HEADING, heading);
35422 }
35423 }
35424 if (event.beta !== null) {
35425 this.set(ol.DeviceOrientation.Property_.BETA,
35426 ol.math.toRadians(event.beta));
35427 }
35428 if (event.gamma !== null) {
35429 this.set(ol.DeviceOrientation.Property_.GAMMA,
35430 ol.math.toRadians(event.gamma));
35431 }
35432 this.changed();
35433};
35434
35435
35436/**
35437 * Rotation around the device z-axis (in radians).
35438 * @return {number|undefined} The euler angle in radians of the device from the
35439 * standard Z axis.
35440 * @observable
35441 * @api
35442 */
35443ol.DeviceOrientation.prototype.getAlpha = function() {
35444 return /** @type {number|undefined} */ (
35445 this.get(ol.DeviceOrientation.Property_.ALPHA));
35446};
35447
35448
35449/**
35450 * Rotation around the device x-axis (in radians).
35451 * @return {number|undefined} The euler angle in radians of the device from the
35452 * planar X axis.
35453 * @observable
35454 * @api
35455 */
35456ol.DeviceOrientation.prototype.getBeta = function() {
35457 return /** @type {number|undefined} */ (
35458 this.get(ol.DeviceOrientation.Property_.BETA));
35459};
35460
35461
35462/**
35463 * Rotation around the device y-axis (in radians).
35464 * @return {number|undefined} The euler angle in radians of the device from the
35465 * planar Y axis.
35466 * @observable
35467 * @api
35468 */
35469ol.DeviceOrientation.prototype.getGamma = function() {
35470 return /** @type {number|undefined} */ (
35471 this.get(ol.DeviceOrientation.Property_.GAMMA));
35472};
35473
35474
35475/**
35476 * The heading of the device relative to north (in radians).
35477 * @return {number|undefined} The heading of the device relative to north, in
35478 * radians, normalizing for different browser behavior.
35479 * @observable
35480 * @api
35481 */
35482ol.DeviceOrientation.prototype.getHeading = function() {
35483 return /** @type {number|undefined} */ (
35484 this.get(ol.DeviceOrientation.Property_.HEADING));
35485};
35486
35487
35488/**
35489 * Determine if orientation is being tracked.
35490 * @return {boolean} Changes in device orientation are being tracked.
35491 * @observable
35492 * @api
35493 */
35494ol.DeviceOrientation.prototype.getTracking = function() {
35495 return /** @type {boolean} */ (
35496 this.get(ol.DeviceOrientation.Property_.TRACKING));
35497};
35498
35499
35500/**
35501 * @private
35502 */
35503ol.DeviceOrientation.prototype.handleTrackingChanged_ = function() {
35504 if (ol.has.DEVICE_ORIENTATION) {
35505 var tracking = this.getTracking();
35506 if (tracking && !this.listenerKey_) {
35507 this.listenerKey_ = ol.events.listen(window, 'deviceorientation',
35508 this.orientationChange_, this);
35509 } else if (!tracking && this.listenerKey_ !== null) {
35510 ol.events.unlistenByKey(this.listenerKey_);
35511 this.listenerKey_ = null;
35512 }
35513 }
35514};
35515
35516
35517/**
35518 * Enable or disable tracking of device orientation events.
35519 * @param {boolean} tracking The status of tracking changes to alpha, beta and
35520 * gamma. If true, changes are tracked and reported immediately.
35521 * @observable
35522 * @api
35523 */
35524ol.DeviceOrientation.prototype.setTracking = function(tracking) {
35525 this.set(ol.DeviceOrientation.Property_.TRACKING, tracking);
35526};
35527
35528
35529/**
35530 * @enum {string}
35531 * @private
35532 */
35533ol.DeviceOrientation.Property_ = {
35534 ALPHA: 'alpha',
35535 BETA: 'beta',
35536 GAMMA: 'gamma',
35537 HEADING: 'heading',
35538 TRACKING: 'tracking'
35539};
35540
35541goog.provide('ol.ImageState');
35542
35543/**
35544 * @enum {number}
35545 */
35546ol.ImageState = {
35547 IDLE: 0,
35548 LOADING: 1,
35549 LOADED: 2,
35550 ERROR: 3
35551};
35552
35553goog.provide('ol.style.Image');
35554
35555
35556/**
35557 * @classdesc
35558 * A base class used for creating subclasses and not instantiated in
35559 * apps. Base class for {@link ol.style.Icon}, {@link ol.style.Circle} and
35560 * {@link ol.style.RegularShape}.
35561 *
35562 * @constructor
35563 * @abstract
35564 * @param {ol.StyleImageOptions} options Options.
35565 * @api
35566 */
35567ol.style.Image = function(options) {
35568
35569 /**
35570 * @private
35571 * @type {number}
35572 */
35573 this.opacity_ = options.opacity;
35574
35575 /**
35576 * @private
35577 * @type {boolean}
35578 */
35579 this.rotateWithView_ = options.rotateWithView;
35580
35581 /**
35582 * @private
35583 * @type {number}
35584 */
35585 this.rotation_ = options.rotation;
35586
35587 /**
35588 * @private
35589 * @type {number}
35590 */
35591 this.scale_ = options.scale;
35592
35593 /**
35594 * @private
35595 * @type {boolean}
35596 */
35597 this.snapToPixel_ = options.snapToPixel;
35598
35599};
35600
35601
35602/**
35603 * Get the symbolizer opacity.
35604 * @return {number} Opacity.
35605 * @api
35606 */
35607ol.style.Image.prototype.getOpacity = function() {
35608 return this.opacity_;
35609};
35610
35611
35612/**
35613 * Determine whether the symbolizer rotates with the map.
35614 * @return {boolean} Rotate with map.
35615 * @api
35616 */
35617ol.style.Image.prototype.getRotateWithView = function() {
35618 return this.rotateWithView_;
35619};
35620
35621
35622/**
35623 * Get the symoblizer rotation.
35624 * @return {number} Rotation.
35625 * @api
35626 */
35627ol.style.Image.prototype.getRotation = function() {
35628 return this.rotation_;
35629};
35630
35631
35632/**
35633 * Get the symbolizer scale.
35634 * @return {number} Scale.
35635 * @api
35636 */
35637ol.style.Image.prototype.getScale = function() {
35638 return this.scale_;
35639};
35640
35641
35642/**
35643 * Determine whether the symbolizer should be snapped to a pixel.
35644 * @return {boolean} The symbolizer should snap to a pixel.
35645 * @api
35646 */
35647ol.style.Image.prototype.getSnapToPixel = function() {
35648 return this.snapToPixel_;
35649};
35650
35651
35652/**
35653 * Get the anchor point in pixels. The anchor determines the center point for the
35654 * symbolizer.
35655 * @abstract
35656 * @return {Array.<number>} Anchor.
35657 */
35658ol.style.Image.prototype.getAnchor = function() {};
35659
35660
35661/**
35662 * Get the image element for the symbolizer.
35663 * @abstract
35664 * @param {number} pixelRatio Pixel ratio.
35665 * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.
35666 */
35667ol.style.Image.prototype.getImage = function(pixelRatio) {};
35668
35669
35670/**
35671 * @abstract
35672 * @param {number} pixelRatio Pixel ratio.
35673 * @return {HTMLCanvasElement|HTMLVideoElement|Image} Image element.
35674 */
35675ol.style.Image.prototype.getHitDetectionImage = function(pixelRatio) {};
35676
35677
35678/**
35679 * @abstract
35680 * @return {ol.ImageState} Image state.
35681 */
35682ol.style.Image.prototype.getImageState = function() {};
35683
35684
35685/**
35686 * @abstract
35687 * @return {ol.Size} Image size.
35688 */
35689ol.style.Image.prototype.getImageSize = function() {};
35690
35691
35692/**
35693 * @abstract
35694 * @return {ol.Size} Size of the hit-detection image.
35695 */
35696ol.style.Image.prototype.getHitDetectionImageSize = function() {};
35697
35698
35699/**
35700 * Get the origin of the symbolizer.
35701 * @abstract
35702 * @return {Array.<number>} Origin.
35703 */
35704ol.style.Image.prototype.getOrigin = function() {};
35705
35706
35707/**
35708 * Get the size of the symbolizer (in pixels).
35709 * @abstract
35710 * @return {ol.Size} Size.
35711 */
35712ol.style.Image.prototype.getSize = function() {};
35713
35714
35715/**
35716 * Set the opacity.
35717 *
35718 * @param {number} opacity Opacity.
35719 * @api
35720 */
35721ol.style.Image.prototype.setOpacity = function(opacity) {
35722 this.opacity_ = opacity;
35723};
35724
35725
35726/**
35727 * Set whether to rotate the style with the view.
35728 *
35729 * @param {boolean} rotateWithView Rotate with map.
35730 */
35731ol.style.Image.prototype.setRotateWithView = function(rotateWithView) {
35732 this.rotateWithView_ = rotateWithView;
35733};
35734
35735
35736/**
35737 * Set the rotation.
35738 *
35739 * @param {number} rotation Rotation.
35740 * @api
35741 */
35742ol.style.Image.prototype.setRotation = function(rotation) {
35743 this.rotation_ = rotation;
35744};
35745
35746
35747/**
35748 * Set the scale.
35749 *
35750 * @param {number} scale Scale.
35751 * @api
35752 */
35753ol.style.Image.prototype.setScale = function(scale) {
35754 this.scale_ = scale;
35755};
35756
35757
35758/**
35759 * Set whether to snap the image to the closest pixel.
35760 *
35761 * @param {boolean} snapToPixel Snap to pixel?
35762 */
35763ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) {
35764 this.snapToPixel_ = snapToPixel;
35765};
35766
35767
35768/**
35769 * @abstract
35770 * @param {function(this: T, ol.events.Event)} listener Listener function.
35771 * @param {T} thisArg Value to use as `this` when executing `listener`.
35772 * @return {ol.EventsKey|undefined} Listener key.
35773 * @template T
35774 */
35775ol.style.Image.prototype.listenImageChange = function(listener, thisArg) {};
35776
35777
35778/**
35779 * Load not yet loaded URI.
35780 * @abstract
35781 */
35782ol.style.Image.prototype.load = function() {};
35783
35784
35785/**
35786 * @abstract
35787 * @param {function(this: T, ol.events.Event)} listener Listener function.
35788 * @param {T} thisArg Value to use as `this` when executing `listener`.
35789 * @template T
35790 */
35791ol.style.Image.prototype.unlistenImageChange = function(listener, thisArg) {};
35792
35793goog.provide('ol.style.RegularShape');
35794
35795goog.require('ol');
35796goog.require('ol.colorlike');
35797goog.require('ol.dom');
35798goog.require('ol.has');
35799goog.require('ol.ImageState');
35800goog.require('ol.render.canvas');
35801goog.require('ol.style.Image');
35802
35803
35804/**
35805 * @classdesc
35806 * Set regular shape style for vector features. The resulting shape will be
35807 * a regular polygon when `radius` is provided, or a star when `radius1` and
35808 * `radius2` are provided.
35809 *
35810 * @constructor
35811 * @param {olx.style.RegularShapeOptions} options Options.
35812 * @extends {ol.style.Image}
35813 * @api
35814 */
35815ol.style.RegularShape = function(options) {
35816 /**
35817 * @private
35818 * @type {Array.<string>}
35819 */
35820 this.checksums_ = null;
35821
35822 /**
35823 * @private
35824 * @type {HTMLCanvasElement}
35825 */
35826 this.canvas_ = null;
35827
35828 /**
35829 * @private
35830 * @type {HTMLCanvasElement}
35831 */
35832 this.hitDetectionCanvas_ = null;
35833
35834 /**
35835 * @private
35836 * @type {ol.style.Fill}
35837 */
35838 this.fill_ = options.fill !== undefined ? options.fill : null;
35839
35840 /**
35841 * @private
35842 * @type {Array.<number>}
35843 */
35844 this.origin_ = [0, 0];
35845
35846 /**
35847 * @private
35848 * @type {number}
35849 */
35850 this.points_ = options.points;
35851
35852 /**
35853 * @protected
35854 * @type {number}
35855 */
35856 this.radius_ = /** @type {number} */ (options.radius !== undefined ?
35857 options.radius : options.radius1);
35858
35859 /**
35860 * @private
35861 * @type {number|undefined}
35862 */
35863 this.radius2_ = options.radius2;
35864
35865 /**
35866 * @private
35867 * @type {number}
35868 */
35869 this.angle_ = options.angle !== undefined ? options.angle : 0;
35870
35871 /**
35872 * @private
35873 * @type {ol.style.Stroke}
35874 */
35875 this.stroke_ = options.stroke !== undefined ? options.stroke : null;
35876
35877 /**
35878 * @private
35879 * @type {Array.<number>}
35880 */
35881 this.anchor_ = null;
35882
35883 /**
35884 * @private
35885 * @type {ol.Size}
35886 */
35887 this.size_ = null;
35888
35889 /**
35890 * @private
35891 * @type {ol.Size}
35892 */
35893 this.imageSize_ = null;
35894
35895 /**
35896 * @private
35897 * @type {ol.Size}
35898 */
35899 this.hitDetectionImageSize_ = null;
35900
35901 /**
35902 * @protected
35903 * @type {ol.style.AtlasManager|undefined}
35904 */
35905 this.atlasManager_ = options.atlasManager;
35906
35907 this.render_(this.atlasManager_);
35908
35909 /**
35910 * @type {boolean}
35911 */
35912 var snapToPixel = options.snapToPixel !== undefined ?
35913 options.snapToPixel : true;
35914
35915 /**
35916 * @type {boolean}
35917 */
35918 var rotateWithView = options.rotateWithView !== undefined ?
35919 options.rotateWithView : false;
35920
35921 ol.style.Image.call(this, {
35922 opacity: 1,
35923 rotateWithView: rotateWithView,
35924 rotation: options.rotation !== undefined ? options.rotation : 0,
35925 scale: 1,
35926 snapToPixel: snapToPixel
35927 });
35928};
35929ol.inherits(ol.style.RegularShape, ol.style.Image);
35930
35931
35932/**
35933 * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.
35934 * @return {ol.style.RegularShape} The cloned style.
35935 * @api
35936 */
35937ol.style.RegularShape.prototype.clone = function() {
35938 var style = new ol.style.RegularShape({
35939 fill: this.getFill() ? this.getFill().clone() : undefined,
35940 points: this.getPoints(),
35941 radius: this.getRadius(),
35942 radius2: this.getRadius2(),
35943 angle: this.getAngle(),
35944 snapToPixel: this.getSnapToPixel(),
35945 stroke: this.getStroke() ? this.getStroke().clone() : undefined,
35946 rotation: this.getRotation(),
35947 rotateWithView: this.getRotateWithView(),
35948 atlasManager: this.atlasManager_
35949 });
35950 style.setOpacity(this.getOpacity());
35951 style.setScale(this.getScale());
35952 return style;
35953};
35954
35955
35956/**
35957 * @inheritDoc
35958 * @api
35959 */
35960ol.style.RegularShape.prototype.getAnchor = function() {
35961 return this.anchor_;
35962};
35963
35964
35965/**
35966 * Get the angle used in generating the shape.
35967 * @return {number} Shape's rotation in radians.
35968 * @api
35969 */
35970ol.style.RegularShape.prototype.getAngle = function() {
35971 return this.angle_;
35972};
35973
35974
35975/**
35976 * Get the fill style for the shape.
35977 * @return {ol.style.Fill} Fill style.
35978 * @api
35979 */
35980ol.style.RegularShape.prototype.getFill = function() {
35981 return this.fill_;
35982};
35983
35984
35985/**
35986 * @inheritDoc
35987 */
35988ol.style.RegularShape.prototype.getHitDetectionImage = function(pixelRatio) {
35989 return this.hitDetectionCanvas_;
35990};
35991
35992
35993/**
35994 * @inheritDoc
35995 * @api
35996 */
35997ol.style.RegularShape.prototype.getImage = function(pixelRatio) {
35998 return this.canvas_;
35999};
36000
36001
36002/**
36003 * @inheritDoc
36004 */
36005ol.style.RegularShape.prototype.getImageSize = function() {
36006 return this.imageSize_;
36007};
36008
36009
36010/**
36011 * @inheritDoc
36012 */
36013ol.style.RegularShape.prototype.getHitDetectionImageSize = function() {
36014 return this.hitDetectionImageSize_;
36015};
36016
36017
36018/**
36019 * @inheritDoc
36020 */
36021ol.style.RegularShape.prototype.getImageState = function() {
36022 return ol.ImageState.LOADED;
36023};
36024
36025
36026/**
36027 * @inheritDoc
36028 * @api
36029 */
36030ol.style.RegularShape.prototype.getOrigin = function() {
36031 return this.origin_;
36032};
36033
36034
36035/**
36036 * Get the number of points for generating the shape.
36037 * @return {number} Number of points for stars and regular polygons.
36038 * @api
36039 */
36040ol.style.RegularShape.prototype.getPoints = function() {
36041 return this.points_;
36042};
36043
36044
36045/**
36046 * Get the (primary) radius for the shape.
36047 * @return {number} Radius.
36048 * @api
36049 */
36050ol.style.RegularShape.prototype.getRadius = function() {
36051 return this.radius_;
36052};
36053
36054
36055/**
36056 * Get the secondary radius for the shape.
36057 * @return {number|undefined} Radius2.
36058 * @api
36059 */
36060ol.style.RegularShape.prototype.getRadius2 = function() {
36061 return this.radius2_;
36062};
36063
36064
36065/**
36066 * @inheritDoc
36067 * @api
36068 */
36069ol.style.RegularShape.prototype.getSize = function() {
36070 return this.size_;
36071};
36072
36073
36074/**
36075 * Get the stroke style for the shape.
36076 * @return {ol.style.Stroke} Stroke style.
36077 * @api
36078 */
36079ol.style.RegularShape.prototype.getStroke = function() {
36080 return this.stroke_;
36081};
36082
36083
36084/**
36085 * @inheritDoc
36086 */
36087ol.style.RegularShape.prototype.listenImageChange = function(listener, thisArg) {};
36088
36089
36090/**
36091 * @inheritDoc
36092 */
36093ol.style.RegularShape.prototype.load = function() {};
36094
36095
36096/**
36097 * @inheritDoc
36098 */
36099ol.style.RegularShape.prototype.unlistenImageChange = function(listener, thisArg) {};
36100
36101
36102/**
36103 * @protected
36104 * @param {ol.style.AtlasManager|undefined} atlasManager An atlas manager.
36105 */
36106ol.style.RegularShape.prototype.render_ = function(atlasManager) {
36107 var imageSize;
36108 var lineCap = '';
36109 var lineJoin = '';
36110 var miterLimit = 0;
36111 var lineDash = null;
36112 var lineDashOffset = 0;
36113 var strokeStyle;
36114 var strokeWidth = 0;
36115
36116 if (this.stroke_) {
36117 strokeStyle = this.stroke_.getColor();
36118 if (strokeStyle === null) {
36119 strokeStyle = ol.render.canvas.defaultStrokeStyle;
36120 }
36121 strokeStyle = ol.colorlike.asColorLike(strokeStyle);
36122 strokeWidth = this.stroke_.getWidth();
36123 if (strokeWidth === undefined) {
36124 strokeWidth = ol.render.canvas.defaultLineWidth;
36125 }
36126 lineDash = this.stroke_.getLineDash();
36127 lineDashOffset = this.stroke_.getLineDashOffset();
36128 if (!ol.has.CANVAS_LINE_DASH) {
36129 lineDash = null;
36130 lineDashOffset = 0;
36131 }
36132 lineJoin = this.stroke_.getLineJoin();
36133 if (lineJoin === undefined) {
36134 lineJoin = ol.render.canvas.defaultLineJoin;
36135 }
36136 lineCap = this.stroke_.getLineCap();
36137 if (lineCap === undefined) {
36138 lineCap = ol.render.canvas.defaultLineCap;
36139 }
36140 miterLimit = this.stroke_.getMiterLimit();
36141 if (miterLimit === undefined) {
36142 miterLimit = ol.render.canvas.defaultMiterLimit;
36143 }
36144 }
36145
36146 var size = 2 * (this.radius_ + strokeWidth) + 1;
36147
36148 /** @type {ol.RegularShapeRenderOptions} */
36149 var renderOptions = {
36150 strokeStyle: strokeStyle,
36151 strokeWidth: strokeWidth,
36152 size: size,
36153 lineCap: lineCap,
36154 lineDash: lineDash,
36155 lineDashOffset: lineDashOffset,
36156 lineJoin: lineJoin,
36157 miterLimit: miterLimit
36158 };
36159
36160 if (atlasManager === undefined) {
36161 // no atlas manager is used, create a new canvas
36162 var context = ol.dom.createCanvasContext2D(size, size);
36163 this.canvas_ = context.canvas;
36164
36165 // canvas.width and height are rounded to the closest integer
36166 size = this.canvas_.width;
36167 imageSize = size;
36168
36169 this.draw_(renderOptions, context, 0, 0);
36170
36171 this.createHitDetectionCanvas_(renderOptions);
36172 } else {
36173 // an atlas manager is used, add the symbol to an atlas
36174 size = Math.round(size);
36175
36176 var hasCustomHitDetectionImage = !this.fill_;
36177 var renderHitDetectionCallback;
36178 if (hasCustomHitDetectionImage) {
36179 // render the hit-detection image into a separate atlas image
36180 renderHitDetectionCallback =
36181 this.drawHitDetectionCanvas_.bind(this, renderOptions);
36182 }
36183
36184 var id = this.getChecksum();
36185 var info = atlasManager.add(
36186 id, size, size, this.draw_.bind(this, renderOptions),
36187 renderHitDetectionCallback);
36188
36189 this.canvas_ = info.image;
36190 this.origin_ = [info.offsetX, info.offsetY];
36191 imageSize = info.image.width;
36192
36193 if (hasCustomHitDetectionImage) {
36194 this.hitDetectionCanvas_ = info.hitImage;
36195 this.hitDetectionImageSize_ =
36196 [info.hitImage.width, info.hitImage.height];
36197 } else {
36198 this.hitDetectionCanvas_ = this.canvas_;
36199 this.hitDetectionImageSize_ = [imageSize, imageSize];
36200 }
36201 }
36202
36203 this.anchor_ = [size / 2, size / 2];
36204 this.size_ = [size, size];
36205 this.imageSize_ = [imageSize, imageSize];
36206};
36207
36208
36209/**
36210 * @private
36211 * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
36212 * @param {CanvasRenderingContext2D} context The rendering context.
36213 * @param {number} x The origin for the symbol (x).
36214 * @param {number} y The origin for the symbol (y).
36215 */
36216ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {
36217 var i, angle0, radiusC;
36218 // reset transform
36219 context.setTransform(1, 0, 0, 1, 0, 0);
36220
36221 // then move to (x, y)
36222 context.translate(x, y);
36223
36224 context.beginPath();
36225
36226 var points = this.points_;
36227 if (points === Infinity) {
36228 context.arc(
36229 renderOptions.size / 2, renderOptions.size / 2,
36230 this.radius_, 0, 2 * Math.PI, true);
36231 } else {
36232 var radius2 = (this.radius2_ !== undefined) ? this.radius2_
36233 : this.radius_;
36234 if (radius2 !== this.radius_) {
36235 points = 2 * points;
36236 }
36237 for (i = 0; i <= points; i++) {
36238 angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;
36239 radiusC = i % 2 === 0 ? this.radius_ : radius2;
36240 context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
36241 renderOptions.size / 2 + radiusC * Math.sin(angle0));
36242 }
36243 }
36244
36245
36246 if (this.fill_) {
36247 var color = this.fill_.getColor();
36248 if (color === null) {
36249 color = ol.render.canvas.defaultFillStyle;
36250 }
36251 context.fillStyle = ol.colorlike.asColorLike(color);
36252 context.fill();
36253 }
36254 if (this.stroke_) {
36255 context.strokeStyle = renderOptions.strokeStyle;
36256 context.lineWidth = renderOptions.strokeWidth;
36257 if (renderOptions.lineDash) {
36258 context.setLineDash(renderOptions.lineDash);
36259 context.lineDashOffset = renderOptions.lineDashOffset;
36260 }
36261 context.lineCap = renderOptions.lineCap;
36262 context.lineJoin = renderOptions.lineJoin;
36263 context.miterLimit = renderOptions.miterLimit;
36264 context.stroke();
36265 }
36266 context.closePath();
36267};
36268
36269
36270/**
36271 * @private
36272 * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
36273 */
36274ol.style.RegularShape.prototype.createHitDetectionCanvas_ = function(renderOptions) {
36275 this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size];
36276 if (this.fill_) {
36277 this.hitDetectionCanvas_ = this.canvas_;
36278 return;
36279 }
36280
36281 // if no fill style is set, create an extra hit-detection image with a
36282 // default fill style
36283 var context = ol.dom.createCanvasContext2D(renderOptions.size, renderOptions.size);
36284 this.hitDetectionCanvas_ = context.canvas;
36285
36286 this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);
36287};
36288
36289
36290/**
36291 * @private
36292 * @param {ol.RegularShapeRenderOptions} renderOptions Render options.
36293 * @param {CanvasRenderingContext2D} context The context.
36294 * @param {number} x The origin for the symbol (x).
36295 * @param {number} y The origin for the symbol (y).
36296 */
36297ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = function(renderOptions, context, x, y) {
36298 // reset transform
36299 context.setTransform(1, 0, 0, 1, 0, 0);
36300
36301 // then move to (x, y)
36302 context.translate(x, y);
36303
36304 context.beginPath();
36305
36306 var points = this.points_;
36307 if (points === Infinity) {
36308 context.arc(
36309 renderOptions.size / 2, renderOptions.size / 2,
36310 this.radius_, 0, 2 * Math.PI, true);
36311 } else {
36312 var radius2 = (this.radius2_ !== undefined) ? this.radius2_
36313 : this.radius_;
36314 if (radius2 !== this.radius_) {
36315 points = 2 * points;
36316 }
36317 var i, radiusC, angle0;
36318 for (i = 0; i <= points; i++) {
36319 angle0 = i * 2 * Math.PI / points - Math.PI / 2 + this.angle_;
36320 radiusC = i % 2 === 0 ? this.radius_ : radius2;
36321 context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
36322 renderOptions.size / 2 + radiusC * Math.sin(angle0));
36323 }
36324 }
36325
36326 context.fillStyle = ol.render.canvas.defaultFillStyle;
36327 context.fill();
36328 if (this.stroke_) {
36329 context.strokeStyle = renderOptions.strokeStyle;
36330 context.lineWidth = renderOptions.strokeWidth;
36331 if (renderOptions.lineDash) {
36332 context.setLineDash(renderOptions.lineDash);
36333 context.lineDashOffset = renderOptions.lineDashOffset;
36334 }
36335 context.stroke();
36336 }
36337 context.closePath();
36338};
36339
36340
36341/**
36342 * @return {string} The checksum.
36343 */
36344ol.style.RegularShape.prototype.getChecksum = function() {
36345 var strokeChecksum = this.stroke_ ?
36346 this.stroke_.getChecksum() : '-';
36347 var fillChecksum = this.fill_ ?
36348 this.fill_.getChecksum() : '-';
36349
36350 var recalculate = !this.checksums_ ||
36351 (strokeChecksum != this.checksums_[1] ||
36352 fillChecksum != this.checksums_[2] ||
36353 this.radius_ != this.checksums_[3] ||
36354 this.radius2_ != this.checksums_[4] ||
36355 this.angle_ != this.checksums_[5] ||
36356 this.points_ != this.checksums_[6]);
36357
36358 if (recalculate) {
36359 var checksum = 'r' + strokeChecksum + fillChecksum +
36360 (this.radius_ !== undefined ? this.radius_.toString() : '-') +
36361 (this.radius2_ !== undefined ? this.radius2_.toString() : '-') +
36362 (this.angle_ !== undefined ? this.angle_.toString() : '-') +
36363 (this.points_ !== undefined ? this.points_.toString() : '-');
36364 this.checksums_ = [checksum, strokeChecksum, fillChecksum,
36365 this.radius_, this.radius2_, this.angle_, this.points_];
36366 }
36367
36368 return this.checksums_[0];
36369};
36370
36371goog.provide('ol.style.Circle');
36372
36373goog.require('ol');
36374goog.require('ol.style.RegularShape');
36375
36376
36377/**
36378 * @classdesc
36379 * Set circle style for vector features.
36380 *
36381 * @constructor
36382 * @param {olx.style.CircleOptions=} opt_options Options.
36383 * @extends {ol.style.RegularShape}
36384 * @api
36385 */
36386ol.style.Circle = function(opt_options) {
36387
36388 var options = opt_options || {};
36389
36390 ol.style.RegularShape.call(this, {
36391 points: Infinity,
36392 fill: options.fill,
36393 radius: options.radius,
36394 snapToPixel: options.snapToPixel,
36395 stroke: options.stroke,
36396 atlasManager: options.atlasManager
36397 });
36398
36399};
36400ol.inherits(ol.style.Circle, ol.style.RegularShape);
36401
36402
36403/**
36404 * Clones the style. If an atlasmanager was provided to the original style it will be used in the cloned style, too.
36405 * @return {ol.style.Circle} The cloned style.
36406 * @override
36407 * @api
36408 */
36409ol.style.Circle.prototype.clone = function() {
36410 var style = new ol.style.Circle({
36411 fill: this.getFill() ? this.getFill().clone() : undefined,
36412 stroke: this.getStroke() ? this.getStroke().clone() : undefined,
36413 radius: this.getRadius(),
36414 snapToPixel: this.getSnapToPixel(),
36415 atlasManager: this.atlasManager_
36416 });
36417 style.setOpacity(this.getOpacity());
36418 style.setScale(this.getScale());
36419 return style;
36420};
36421
36422
36423/**
36424 * Set the circle radius.
36425 *
36426 * @param {number} radius Circle radius.
36427 * @api
36428 */
36429ol.style.Circle.prototype.setRadius = function(radius) {
36430 this.radius_ = radius;
36431 this.render_(this.atlasManager_);
36432};
36433
36434goog.provide('ol.style.Fill');
36435
36436goog.require('ol');
36437goog.require('ol.color');
36438
36439
36440/**
36441 * @classdesc
36442 * Set fill style for vector features.
36443 *
36444 * @constructor
36445 * @param {olx.style.FillOptions=} opt_options Options.
36446 * @api
36447 */
36448ol.style.Fill = function(opt_options) {
36449
36450 var options = opt_options || {};
36451
36452 /**
36453 * @private
36454 * @type {ol.Color|ol.ColorLike}
36455 */
36456 this.color_ = options.color !== undefined ? options.color : null;
36457
36458 /**
36459 * @private
36460 * @type {string|undefined}
36461 */
36462 this.checksum_ = undefined;
36463};
36464
36465
36466/**
36467 * Clones the style. The color is not cloned if it is an {@link ol.ColorLike}.
36468 * @return {ol.style.Fill} The cloned style.
36469 * @api
36470 */
36471ol.style.Fill.prototype.clone = function() {
36472 var color = this.getColor();
36473 return new ol.style.Fill({
36474 color: (color && color.slice) ? color.slice() : color || undefined
36475 });
36476};
36477
36478
36479/**
36480 * Get the fill color.
36481 * @return {ol.Color|ol.ColorLike} Color.
36482 * @api
36483 */
36484ol.style.Fill.prototype.getColor = function() {
36485 return this.color_;
36486};
36487
36488
36489/**
36490 * Set the color.
36491 *
36492 * @param {ol.Color|ol.ColorLike} color Color.
36493 * @api
36494 */
36495ol.style.Fill.prototype.setColor = function(color) {
36496 this.color_ = color;
36497 this.checksum_ = undefined;
36498};
36499
36500
36501/**
36502 * @return {string} The checksum.
36503 */
36504ol.style.Fill.prototype.getChecksum = function() {
36505 if (this.checksum_ === undefined) {
36506 if (
36507 this.color_ instanceof CanvasPattern ||
36508 this.color_ instanceof CanvasGradient
36509 ) {
36510 this.checksum_ = ol.getUid(this.color_).toString();
36511 } else {
36512 this.checksum_ = 'f' + (this.color_ ?
36513 ol.color.asString(this.color_) : '-');
36514 }
36515 }
36516
36517 return this.checksum_;
36518};
36519
36520goog.provide('ol.style.Style');
36521
36522goog.require('ol.asserts');
36523goog.require('ol.geom.GeometryType');
36524goog.require('ol.style.Circle');
36525goog.require('ol.style.Fill');
36526goog.require('ol.style.Stroke');
36527
36528
36529/**
36530 * @classdesc
36531 * Container for vector feature rendering styles. Any changes made to the style
36532 * or its children through `set*()` methods will not take effect until the
36533 * feature or layer that uses the style is re-rendered.
36534 *
36535 * @constructor
36536 * @struct
36537 * @param {olx.style.StyleOptions=} opt_options Style options.
36538 * @api
36539 */
36540ol.style.Style = function(opt_options) {
36541
36542 var options = opt_options || {};
36543
36544 /**
36545 * @private
36546 * @type {string|ol.geom.Geometry|ol.StyleGeometryFunction}
36547 */
36548 this.geometry_ = null;
36549
36550 /**
36551 * @private
36552 * @type {!ol.StyleGeometryFunction}
36553 */
36554 this.geometryFunction_ = ol.style.Style.defaultGeometryFunction;
36555
36556 if (options.geometry !== undefined) {
36557 this.setGeometry(options.geometry);
36558 }
36559
36560 /**
36561 * @private
36562 * @type {ol.style.Fill}
36563 */
36564 this.fill_ = options.fill !== undefined ? options.fill : null;
36565
36566 /**
36567 * @private
36568 * @type {ol.style.Image}
36569 */
36570 this.image_ = options.image !== undefined ? options.image : null;
36571
36572 /**
36573 * @private
36574 * @type {ol.StyleRenderFunction|null}
36575 */
36576 this.renderer_ = options.renderer !== undefined ? options.renderer : null;
36577
36578 /**
36579 * @private
36580 * @type {ol.style.Stroke}
36581 */
36582 this.stroke_ = options.stroke !== undefined ? options.stroke : null;
36583
36584 /**
36585 * @private
36586 * @type {ol.style.Text}
36587 */
36588 this.text_ = options.text !== undefined ? options.text : null;
36589
36590 /**
36591 * @private
36592 * @type {number|undefined}
36593 */
36594 this.zIndex_ = options.zIndex;
36595
36596};
36597
36598
36599/**
36600 * Clones the style.
36601 * @return {ol.style.Style} The cloned style.
36602 * @api
36603 */
36604ol.style.Style.prototype.clone = function() {
36605 var geometry = this.getGeometry();
36606 if (geometry && geometry.clone) {
36607 geometry = geometry.clone();
36608 }
36609 return new ol.style.Style({
36610 geometry: geometry,
36611 fill: this.getFill() ? this.getFill().clone() : undefined,
36612 image: this.getImage() ? this.getImage().clone() : undefined,
36613 stroke: this.getStroke() ? this.getStroke().clone() : undefined,
36614 text: this.getText() ? this.getText().clone() : undefined,
36615 zIndex: this.getZIndex()
36616 });
36617};
36618
36619
36620/**
36621 * Get the custom renderer function that was configured with
36622 * {@link #setRenderer} or the `renderer` constructor option.
36623 * @return {ol.StyleRenderFunction|null} Custom renderer function.
36624 * @api
36625 */
36626ol.style.Style.prototype.getRenderer = function() {
36627 return this.renderer_;
36628};
36629
36630
36631/**
36632 * Sets a custom renderer function for this style. When set, `fill`, `stroke`
36633 * and `image` options of the style will be ignored.
36634 * @param {ol.StyleRenderFunction|null} renderer Custom renderer function.
36635 * @api
36636 */
36637ol.style.Style.prototype.setRenderer = function(renderer) {
36638 this.renderer_ = renderer;
36639};
36640
36641
36642/**
36643 * Get the geometry to be rendered.
36644 * @return {string|ol.geom.Geometry|ol.StyleGeometryFunction}
36645 * Feature property or geometry or function that returns the geometry that will
36646 * be rendered with this style.
36647 * @api
36648 */
36649ol.style.Style.prototype.getGeometry = function() {
36650 return this.geometry_;
36651};
36652
36653
36654/**
36655 * Get the function used to generate a geometry for rendering.
36656 * @return {!ol.StyleGeometryFunction} Function that is called with a feature
36657 * and returns the geometry to render instead of the feature's geometry.
36658 * @api
36659 */
36660ol.style.Style.prototype.getGeometryFunction = function() {
36661 return this.geometryFunction_;
36662};
36663
36664
36665/**
36666 * Get the fill style.
36667 * @return {ol.style.Fill} Fill style.
36668 * @api
36669 */
36670ol.style.Style.prototype.getFill = function() {
36671 return this.fill_;
36672};
36673
36674
36675/**
36676 * Set the fill style.
36677 * @param {ol.style.Fill} fill Fill style.
36678 * @api
36679 */
36680ol.style.Style.prototype.setFill = function(fill) {
36681 this.fill_ = fill;
36682};
36683
36684
36685/**
36686 * Get the image style.
36687 * @return {ol.style.Image} Image style.
36688 * @api
36689 */
36690ol.style.Style.prototype.getImage = function() {
36691 return this.image_;
36692};
36693
36694
36695/**
36696 * Set the image style.
36697 * @param {ol.style.Image} image Image style.
36698 * @api
36699 */
36700ol.style.Style.prototype.setImage = function(image) {
36701 this.image_ = image;
36702};
36703
36704
36705/**
36706 * Get the stroke style.
36707 * @return {ol.style.Stroke} Stroke style.
36708 * @api
36709 */
36710ol.style.Style.prototype.getStroke = function() {
36711 return this.stroke_;
36712};
36713
36714
36715/**
36716 * Set the stroke style.
36717 * @param {ol.style.Stroke} stroke Stroke style.
36718 * @api
36719 */
36720ol.style.Style.prototype.setStroke = function(stroke) {
36721 this.stroke_ = stroke;
36722};
36723
36724
36725/**
36726 * Get the text style.
36727 * @return {ol.style.Text} Text style.
36728 * @api
36729 */
36730ol.style.Style.prototype.getText = function() {
36731 return this.text_;
36732};
36733
36734
36735/**
36736 * Set the text style.
36737 * @param {ol.style.Text} text Text style.
36738 * @api
36739 */
36740ol.style.Style.prototype.setText = function(text) {
36741 this.text_ = text;
36742};
36743
36744
36745/**
36746 * Get the z-index for the style.
36747 * @return {number|undefined} ZIndex.
36748 * @api
36749 */
36750ol.style.Style.prototype.getZIndex = function() {
36751 return this.zIndex_;
36752};
36753
36754
36755/**
36756 * Set a geometry that is rendered instead of the feature's geometry.
36757 *
36758 * @param {string|ol.geom.Geometry|ol.StyleGeometryFunction} geometry
36759 * Feature property or geometry or function returning a geometry to render
36760 * for this style.
36761 * @api
36762 */
36763ol.style.Style.prototype.setGeometry = function(geometry) {
36764 if (typeof geometry === 'function') {
36765 this.geometryFunction_ = geometry;
36766 } else if (typeof geometry === 'string') {
36767 this.geometryFunction_ = function(feature) {
36768 return /** @type {ol.geom.Geometry} */ (feature.get(geometry));
36769 };
36770 } else if (!geometry) {
36771 this.geometryFunction_ = ol.style.Style.defaultGeometryFunction;
36772 } else if (geometry !== undefined) {
36773 this.geometryFunction_ = function() {
36774 return /** @type {ol.geom.Geometry} */ (geometry);
36775 };
36776 }
36777 this.geometry_ = geometry;
36778};
36779
36780
36781/**
36782 * Set the z-index.
36783 *
36784 * @param {number|undefined} zIndex ZIndex.
36785 * @api
36786 */
36787ol.style.Style.prototype.setZIndex = function(zIndex) {
36788 this.zIndex_ = zIndex;
36789};
36790
36791
36792/**
36793 * Convert the provided object into a style function. Functions passed through
36794 * unchanged. Arrays of ol.style.Style or single style objects wrapped in a
36795 * new style function.
36796 * @param {ol.StyleFunction|Array.<ol.style.Style>|ol.style.Style} obj
36797 * A style function, a single style, or an array of styles.
36798 * @return {ol.StyleFunction} A style function.
36799 */
36800ol.style.Style.createFunction = function(obj) {
36801 var styleFunction;
36802
36803 if (typeof obj === 'function') {
36804 styleFunction = obj;
36805 } else {
36806 /**
36807 * @type {Array.<ol.style.Style>}
36808 */
36809 var styles;
36810 if (Array.isArray(obj)) {
36811 styles = obj;
36812 } else {
36813 ol.asserts.assert(obj instanceof ol.style.Style,
36814 41); // Expected an `ol.style.Style` or an array of `ol.style.Style`
36815 styles = [obj];
36816 }
36817 styleFunction = function() {
36818 return styles;
36819 };
36820 }
36821 return styleFunction;
36822};
36823
36824
36825/**
36826 * @type {Array.<ol.style.Style>}
36827 * @private
36828 */
36829ol.style.Style.default_ = null;
36830
36831
36832/**
36833 * @param {ol.Feature|ol.render.Feature} feature Feature.
36834 * @param {number} resolution Resolution.
36835 * @return {Array.<ol.style.Style>} Style.
36836 */
36837ol.style.Style.defaultFunction = function(feature, resolution) {
36838 // We don't use an immediately-invoked function
36839 // and a closure so we don't get an error at script evaluation time in
36840 // browsers that do not support Canvas. (ol.style.Circle does
36841 // canvas.getContext('2d') at construction time, which will cause an.error
36842 // in such browsers.)
36843 if (!ol.style.Style.default_) {
36844 var fill = new ol.style.Fill({
36845 color: 'rgba(255,255,255,0.4)'
36846 });
36847 var stroke = new ol.style.Stroke({
36848 color: '#3399CC',
36849 width: 1.25
36850 });
36851 ol.style.Style.default_ = [
36852 new ol.style.Style({
36853 image: new ol.style.Circle({
36854 fill: fill,
36855 stroke: stroke,
36856 radius: 5
36857 }),
36858 fill: fill,
36859 stroke: stroke
36860 })
36861 ];
36862 }
36863 return ol.style.Style.default_;
36864};
36865
36866
36867/**
36868 * Default styles for editing features.
36869 * @return {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} Styles
36870 */
36871ol.style.Style.createDefaultEditing = function() {
36872 /** @type {Object.<ol.geom.GeometryType, Array.<ol.style.Style>>} */
36873 var styles = {};
36874 var white = [255, 255, 255, 1];
36875 var blue = [0, 153, 255, 1];
36876 var width = 3;
36877 styles[ol.geom.GeometryType.POLYGON] = [
36878 new ol.style.Style({
36879 fill: new ol.style.Fill({
36880 color: [255, 255, 255, 0.5]
36881 })
36882 })
36883 ];
36884 styles[ol.geom.GeometryType.MULTI_POLYGON] =
36885 styles[ol.geom.GeometryType.POLYGON];
36886
36887 styles[ol.geom.GeometryType.LINE_STRING] = [
36888 new ol.style.Style({
36889 stroke: new ol.style.Stroke({
36890 color: white,
36891 width: width + 2
36892 })
36893 }),
36894 new ol.style.Style({
36895 stroke: new ol.style.Stroke({
36896 color: blue,
36897 width: width
36898 })
36899 })
36900 ];
36901 styles[ol.geom.GeometryType.MULTI_LINE_STRING] =
36902 styles[ol.geom.GeometryType.LINE_STRING];
36903
36904 styles[ol.geom.GeometryType.CIRCLE] =
36905 styles[ol.geom.GeometryType.POLYGON].concat(
36906 styles[ol.geom.GeometryType.LINE_STRING]
36907 );
36908
36909
36910 styles[ol.geom.GeometryType.POINT] = [
36911 new ol.style.Style({
36912 image: new ol.style.Circle({
36913 radius: width * 2,
36914 fill: new ol.style.Fill({
36915 color: blue
36916 }),
36917 stroke: new ol.style.Stroke({
36918 color: white,
36919 width: width / 2
36920 })
36921 }),
36922 zIndex: Infinity
36923 })
36924 ];
36925 styles[ol.geom.GeometryType.MULTI_POINT] =
36926 styles[ol.geom.GeometryType.POINT];
36927
36928 styles[ol.geom.GeometryType.GEOMETRY_COLLECTION] =
36929 styles[ol.geom.GeometryType.POLYGON].concat(
36930 styles[ol.geom.GeometryType.LINE_STRING],
36931 styles[ol.geom.GeometryType.POINT]
36932 );
36933
36934 return styles;
36935};
36936
36937
36938/**
36939 * Function that is called with a feature and returns its default geometry.
36940 * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry
36941 * for.
36942 * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render.
36943 */
36944ol.style.Style.defaultGeometryFunction = function(feature) {
36945 return feature.getGeometry();
36946};
36947
36948goog.provide('ol.Feature');
36949
36950goog.require('ol.asserts');
36951goog.require('ol.events');
36952goog.require('ol.events.EventType');
36953goog.require('ol');
36954goog.require('ol.Object');
36955goog.require('ol.geom.Geometry');
36956goog.require('ol.style.Style');
36957
36958
36959/**
36960 * @classdesc
36961 * A vector object for geographic features with a geometry and other
36962 * attribute properties, similar to the features in vector file formats like
36963 * GeoJSON.
36964 *
36965 * Features can be styled individually with `setStyle`; otherwise they use the
36966 * style of their vector layer.
36967 *
36968 * Note that attribute properties are set as {@link ol.Object} properties on
36969 * the feature object, so they are observable, and have get/set accessors.
36970 *
36971 * Typically, a feature has a single geometry property. You can set the
36972 * geometry using the `setGeometry` method and get it with `getGeometry`.
36973 * It is possible to store more than one geometry on a feature using attribute
36974 * properties. By default, the geometry used for rendering is identified by
36975 * the property name `geometry`. If you want to use another geometry property
36976 * for rendering, use the `setGeometryName` method to change the attribute
36977 * property associated with the geometry for the feature. For example:
36978 *
36979 * ```js
36980 * var feature = new ol.Feature({
36981 * geometry: new ol.geom.Polygon(polyCoords),
36982 * labelPoint: new ol.geom.Point(labelCoords),
36983 * name: 'My Polygon'
36984 * });
36985 *
36986 * // get the polygon geometry
36987 * var poly = feature.getGeometry();
36988 *
36989 * // Render the feature as a point using the coordinates from labelPoint
36990 * feature.setGeometryName('labelPoint');
36991 *
36992 * // get the point geometry
36993 * var point = feature.getGeometry();
36994 * ```
36995 *
36996 * @constructor
36997 * @extends {ol.Object}
36998 * @param {ol.geom.Geometry|Object.<string, *>=} opt_geometryOrProperties
36999 * You may pass a Geometry object directly, or an object literal
37000 * containing properties. If you pass an object literal, you may
37001 * include a Geometry associated with a `geometry` key.
37002 * @api
37003 */
37004ol.Feature = function(opt_geometryOrProperties) {
37005
37006 ol.Object.call(this);
37007
37008 /**
37009 * @private
37010 * @type {number|string|undefined}
37011 */
37012 this.id_ = undefined;
37013
37014 /**
37015 * @type {string}
37016 * @private
37017 */
37018 this.geometryName_ = 'geometry';
37019
37020 /**
37021 * User provided style.
37022 * @private
37023 * @type {ol.style.Style|Array.<ol.style.Style>|
37024 * ol.FeatureStyleFunction}
37025 */
37026 this.style_ = null;
37027
37028 /**
37029 * @private
37030 * @type {ol.FeatureStyleFunction|undefined}
37031 */
37032 this.styleFunction_ = undefined;
37033
37034 /**
37035 * @private
37036 * @type {?ol.EventsKey}
37037 */
37038 this.geometryChangeKey_ = null;
37039
37040 ol.events.listen(
37041 this, ol.Object.getChangeEventType(this.geometryName_),
37042 this.handleGeometryChanged_, this);
37043
37044 if (opt_geometryOrProperties !== undefined) {
37045 if (opt_geometryOrProperties instanceof ol.geom.Geometry ||
37046 !opt_geometryOrProperties) {
37047 var geometry = opt_geometryOrProperties;
37048 this.setGeometry(geometry);
37049 } else {
37050 /** @type {Object.<string, *>} */
37051 var properties = opt_geometryOrProperties;
37052 this.setProperties(properties);
37053 }
37054 }
37055};
37056ol.inherits(ol.Feature, ol.Object);
37057
37058
37059/**
37060 * Clone this feature. If the original feature has a geometry it
37061 * is also cloned. The feature id is not set in the clone.
37062 * @return {ol.Feature} The clone.
37063 * @api
37064 */
37065ol.Feature.prototype.clone = function() {
37066 var clone = new ol.Feature(this.getProperties());
37067 clone.setGeometryName(this.getGeometryName());
37068 var geometry = this.getGeometry();
37069 if (geometry) {
37070 clone.setGeometry(geometry.clone());
37071 }
37072 var style = this.getStyle();
37073 if (style) {
37074 clone.setStyle(style);
37075 }
37076 return clone;
37077};
37078
37079
37080/**
37081 * Get the feature's default geometry. A feature may have any number of named
37082 * geometries. The "default" geometry (the one that is rendered by default) is
37083 * set when calling {@link ol.Feature#setGeometry}.
37084 * @return {ol.geom.Geometry|undefined} The default geometry for the feature.
37085 * @api
37086 * @observable
37087 */
37088ol.Feature.prototype.getGeometry = function() {
37089 return /** @type {ol.geom.Geometry|undefined} */ (
37090 this.get(this.geometryName_));
37091};
37092
37093
37094/**
37095 * Get the feature identifier. This is a stable identifier for the feature and
37096 * is either set when reading data from a remote source or set explicitly by
37097 * calling {@link ol.Feature#setId}.
37098 * @return {number|string|undefined} Id.
37099 * @api
37100 */
37101ol.Feature.prototype.getId = function() {
37102 return this.id_;
37103};
37104
37105
37106/**
37107 * Get the name of the feature's default geometry. By default, the default
37108 * geometry is named `geometry`.
37109 * @return {string} Get the property name associated with the default geometry
37110 * for this feature.
37111 * @api
37112 */
37113ol.Feature.prototype.getGeometryName = function() {
37114 return this.geometryName_;
37115};
37116
37117
37118/**
37119 * Get the feature's style. Will return what was provided to the
37120 * {@link ol.Feature#setStyle} method.
37121 * @return {ol.style.Style|Array.<ol.style.Style>|
37122 * ol.FeatureStyleFunction|ol.StyleFunction} The feature style.
37123 * @api
37124 */
37125ol.Feature.prototype.getStyle = function() {
37126 return this.style_;
37127};
37128
37129
37130/**
37131 * Get the feature's style function.
37132 * @return {ol.FeatureStyleFunction|undefined} Return a function
37133 * representing the current style of this feature.
37134 * @api
37135 */
37136ol.Feature.prototype.getStyleFunction = function() {
37137 return this.styleFunction_;
37138};
37139
37140
37141/**
37142 * @private
37143 */
37144ol.Feature.prototype.handleGeometryChange_ = function() {
37145 this.changed();
37146};
37147
37148
37149/**
37150 * @private
37151 */
37152ol.Feature.prototype.handleGeometryChanged_ = function() {
37153 if (this.geometryChangeKey_) {
37154 ol.events.unlistenByKey(this.geometryChangeKey_);
37155 this.geometryChangeKey_ = null;
37156 }
37157 var geometry = this.getGeometry();
37158 if (geometry) {
37159 this.geometryChangeKey_ = ol.events.listen(geometry,
37160 ol.events.EventType.CHANGE, this.handleGeometryChange_, this);
37161 }
37162 this.changed();
37163};
37164
37165
37166/**
37167 * Set the default geometry for the feature. This will update the property
37168 * with the name returned by {@link ol.Feature#getGeometryName}.
37169 * @param {ol.geom.Geometry|undefined} geometry The new geometry.
37170 * @api
37171 * @observable
37172 */
37173ol.Feature.prototype.setGeometry = function(geometry) {
37174 this.set(this.geometryName_, geometry);
37175};
37176
37177
37178/**
37179 * Set the style for the feature. This can be a single style object, an array
37180 * of styles, or a function that takes a resolution and returns an array of
37181 * styles. If it is `null` the feature has no style (a `null` style).
37182 * @param {ol.style.Style|Array.<ol.style.Style>|
37183 * ol.FeatureStyleFunction|ol.StyleFunction} style Style for this feature.
37184 * @api
37185 * @fires ol.events.Event#event:change
37186 */
37187ol.Feature.prototype.setStyle = function(style) {
37188 this.style_ = style;
37189 this.styleFunction_ = !style ?
37190 undefined : ol.Feature.createStyleFunction(style);
37191 this.changed();
37192};
37193
37194
37195/**
37196 * Set the feature id. The feature id is considered stable and may be used when
37197 * requesting features or comparing identifiers returned from a remote source.
37198 * The feature id can be used with the {@link ol.source.Vector#getFeatureById}
37199 * method.
37200 * @param {number|string|undefined} id The feature id.
37201 * @api
37202 * @fires ol.events.Event#event:change
37203 */
37204ol.Feature.prototype.setId = function(id) {
37205 this.id_ = id;
37206 this.changed();
37207};
37208
37209
37210/**
37211 * Set the property name to be used when getting the feature's default geometry.
37212 * When calling {@link ol.Feature#getGeometry}, the value of the property with
37213 * this name will be returned.
37214 * @param {string} name The property name of the default geometry.
37215 * @api
37216 */
37217ol.Feature.prototype.setGeometryName = function(name) {
37218 ol.events.unlisten(
37219 this, ol.Object.getChangeEventType(this.geometryName_),
37220 this.handleGeometryChanged_, this);
37221 this.geometryName_ = name;
37222 ol.events.listen(
37223 this, ol.Object.getChangeEventType(this.geometryName_),
37224 this.handleGeometryChanged_, this);
37225 this.handleGeometryChanged_();
37226};
37227
37228
37229/**
37230 * Convert the provided object into a feature style function. Functions passed
37231 * through unchanged. Arrays of ol.style.Style or single style objects wrapped
37232 * in a new feature style function.
37233 * @param {ol.FeatureStyleFunction|!Array.<ol.style.Style>|!ol.style.Style} obj
37234 * A feature style function, a single style, or an array of styles.
37235 * @return {ol.FeatureStyleFunction} A style function.
37236 */
37237ol.Feature.createStyleFunction = function(obj) {
37238 var styleFunction;
37239
37240 if (typeof obj === 'function') {
37241 if (obj.length == 2) {
37242 styleFunction = function(resolution) {
37243 return /** @type {ol.StyleFunction} */ (obj)(this, resolution);
37244 };
37245 } else {
37246 styleFunction = obj;
37247 }
37248 } else {
37249 /**
37250 * @type {Array.<ol.style.Style>}
37251 */
37252 var styles;
37253 if (Array.isArray(obj)) {
37254 styles = obj;
37255 } else {
37256 ol.asserts.assert(obj instanceof ol.style.Style,
37257 41); // Expected an `ol.style.Style` or an array of `ol.style.Style`
37258 styles = [obj];
37259 }
37260 styleFunction = function() {
37261 return styles;
37262 };
37263 }
37264 return styleFunction;
37265};
37266
37267goog.provide('ol.format.FormatType');
37268
37269
37270/**
37271 * @enum {string}
37272 */
37273ol.format.FormatType = {
37274 ARRAY_BUFFER: 'arraybuffer',
37275 JSON: 'json',
37276 TEXT: 'text',
37277 XML: 'xml'
37278};
37279
37280goog.provide('ol.xml');
37281
37282goog.require('ol.array');
37283
37284
37285/**
37286 * This document should be used when creating nodes for XML serializations. This
37287 * document is also used by {@link ol.xml.createElementNS} and
37288 * {@link ol.xml.setAttributeNS}
37289 * @const
37290 * @type {Document}
37291 */
37292ol.xml.DOCUMENT = document.implementation.createDocument('', '', null);
37293
37294
37295/**
37296 * @param {string} namespaceURI Namespace URI.
37297 * @param {string} qualifiedName Qualified name.
37298 * @return {Node} Node.
37299 */
37300ol.xml.createElementNS = function(namespaceURI, qualifiedName) {
37301 return ol.xml.DOCUMENT.createElementNS(namespaceURI, qualifiedName);
37302};
37303
37304
37305/**
37306 * Recursively grab all text content of child nodes into a single string.
37307 * @param {Node} node Node.
37308 * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line
37309 * breaks.
37310 * @return {string} All text content.
37311 * @api
37312 */
37313ol.xml.getAllTextContent = function(node, normalizeWhitespace) {
37314 return ol.xml.getAllTextContent_(node, normalizeWhitespace, []).join('');
37315};
37316
37317
37318/**
37319 * Recursively grab all text content of child nodes into a single string.
37320 * @param {Node} node Node.
37321 * @param {boolean} normalizeWhitespace Normalize whitespace: remove all line
37322 * breaks.
37323 * @param {Array.<string>} accumulator Accumulator.
37324 * @private
37325 * @return {Array.<string>} Accumulator.
37326 */
37327ol.xml.getAllTextContent_ = function(node, normalizeWhitespace, accumulator) {
37328 if (node.nodeType == Node.CDATA_SECTION_NODE ||
37329 node.nodeType == Node.TEXT_NODE) {
37330 if (normalizeWhitespace) {
37331 accumulator.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
37332 } else {
37333 accumulator.push(node.nodeValue);
37334 }
37335 } else {
37336 var n;
37337 for (n = node.firstChild; n; n = n.nextSibling) {
37338 ol.xml.getAllTextContent_(n, normalizeWhitespace, accumulator);
37339 }
37340 }
37341 return accumulator;
37342};
37343
37344
37345/**
37346 * @param {?} value Value.
37347 * @return {boolean} Is document.
37348 */
37349ol.xml.isDocument = function(value) {
37350 return value instanceof Document;
37351};
37352
37353
37354/**
37355 * @param {?} value Value.
37356 * @return {boolean} Is node.
37357 */
37358ol.xml.isNode = function(value) {
37359 return value instanceof Node;
37360};
37361
37362
37363/**
37364 * @param {Node} node Node.
37365 * @param {?string} namespaceURI Namespace URI.
37366 * @param {string} name Attribute name.
37367 * @return {string} Value
37368 */
37369ol.xml.getAttributeNS = function(node, namespaceURI, name) {
37370 return node.getAttributeNS(namespaceURI, name) || '';
37371};
37372
37373
37374/**
37375 * @param {Node} node Node.
37376 * @param {?string} namespaceURI Namespace URI.
37377 * @param {string} name Attribute name.
37378 * @param {string|number} value Value.
37379 */
37380ol.xml.setAttributeNS = function(node, namespaceURI, name, value) {
37381 node.setAttributeNS(namespaceURI, name, value);
37382};
37383
37384
37385/**
37386 * Parse an XML string to an XML Document.
37387 * @param {string} xml XML.
37388 * @return {Document} Document.
37389 * @api
37390 */
37391ol.xml.parse = function(xml) {
37392 return new DOMParser().parseFromString(xml, 'application/xml');
37393};
37394
37395
37396/**
37397 * Make an array extender function for extending the array at the top of the
37398 * object stack.
37399 * @param {function(this: T, Node, Array.<*>): (Array.<*>|undefined)}
37400 * valueReader Value reader.
37401 * @param {T=} opt_this The object to use as `this` in `valueReader`.
37402 * @return {ol.XmlParser} Parser.
37403 * @template T
37404 */
37405ol.xml.makeArrayExtender = function(valueReader, opt_this) {
37406 return (
37407 /**
37408 * @param {Node} node Node.
37409 * @param {Array.<*>} objectStack Object stack.
37410 */
37411 function(node, objectStack) {
37412 var value = valueReader.call(opt_this, node, objectStack);
37413 if (value !== undefined) {
37414 var array = /** @type {Array.<*>} */
37415 (objectStack[objectStack.length - 1]);
37416 ol.array.extend(array, value);
37417 }
37418 });
37419};
37420
37421
37422/**
37423 * Make an array pusher function for pushing to the array at the top of the
37424 * object stack.
37425 * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
37426 * @param {T=} opt_this The object to use as `this` in `valueReader`.
37427 * @return {ol.XmlParser} Parser.
37428 * @template T
37429 */
37430ol.xml.makeArrayPusher = function(valueReader, opt_this) {
37431 return (
37432 /**
37433 * @param {Node} node Node.
37434 * @param {Array.<*>} objectStack Object stack.
37435 */
37436 function(node, objectStack) {
37437 var value = valueReader.call(opt_this !== undefined ? opt_this : this,
37438 node, objectStack);
37439 if (value !== undefined) {
37440 var array = objectStack[objectStack.length - 1];
37441 array.push(value);
37442 }
37443 });
37444};
37445
37446
37447/**
37448 * Make an object stack replacer function for replacing the object at the
37449 * top of the stack.
37450 * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
37451 * @param {T=} opt_this The object to use as `this` in `valueReader`.
37452 * @return {ol.XmlParser} Parser.
37453 * @template T
37454 */
37455ol.xml.makeReplacer = function(valueReader, opt_this) {
37456 return (
37457 /**
37458 * @param {Node} node Node.
37459 * @param {Array.<*>} objectStack Object stack.
37460 */
37461 function(node, objectStack) {
37462 var value = valueReader.call(opt_this !== undefined ? opt_this : this,
37463 node, objectStack);
37464 if (value !== undefined) {
37465 objectStack[objectStack.length - 1] = value;
37466 }
37467 });
37468};
37469
37470
37471/**
37472 * Make an object property pusher function for adding a property to the
37473 * object at the top of the stack.
37474 * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
37475 * @param {string=} opt_property Property.
37476 * @param {T=} opt_this The object to use as `this` in `valueReader`.
37477 * @return {ol.XmlParser} Parser.
37478 * @template T
37479 */
37480ol.xml.makeObjectPropertyPusher = function(valueReader, opt_property, opt_this) {
37481 return (
37482 /**
37483 * @param {Node} node Node.
37484 * @param {Array.<*>} objectStack Object stack.
37485 */
37486 function(node, objectStack) {
37487 var value = valueReader.call(opt_this !== undefined ? opt_this : this,
37488 node, objectStack);
37489 if (value !== undefined) {
37490 var object = /** @type {Object} */
37491 (objectStack[objectStack.length - 1]);
37492 var property = opt_property !== undefined ?
37493 opt_property : node.localName;
37494 var array;
37495 if (property in object) {
37496 array = object[property];
37497 } else {
37498 array = object[property] = [];
37499 }
37500 array.push(value);
37501 }
37502 });
37503};
37504
37505
37506/**
37507 * Make an object property setter function.
37508 * @param {function(this: T, Node, Array.<*>): *} valueReader Value reader.
37509 * @param {string=} opt_property Property.
37510 * @param {T=} opt_this The object to use as `this` in `valueReader`.
37511 * @return {ol.XmlParser} Parser.
37512 * @template T
37513 */
37514ol.xml.makeObjectPropertySetter = function(valueReader, opt_property, opt_this) {
37515 return (
37516 /**
37517 * @param {Node} node Node.
37518 * @param {Array.<*>} objectStack Object stack.
37519 */
37520 function(node, objectStack) {
37521 var value = valueReader.call(opt_this !== undefined ? opt_this : this,
37522 node, objectStack);
37523 if (value !== undefined) {
37524 var object = /** @type {Object} */
37525 (objectStack[objectStack.length - 1]);
37526 var property = opt_property !== undefined ?
37527 opt_property : node.localName;
37528 object[property] = value;
37529 }
37530 });
37531};
37532
37533
37534/**
37535 * Create a serializer that appends nodes written by its `nodeWriter` to its
37536 * designated parent. The parent is the `node` of the
37537 * {@link ol.XmlNodeStackItem} at the top of the `objectStack`.
37538 * @param {function(this: T, Node, V, Array.<*>)}
37539 * nodeWriter Node writer.
37540 * @param {T=} opt_this The object to use as `this` in `nodeWriter`.
37541 * @return {ol.XmlSerializer} Serializer.
37542 * @template T, V
37543 */
37544ol.xml.makeChildAppender = function(nodeWriter, opt_this) {
37545 return function(node, value, objectStack) {
37546 nodeWriter.call(opt_this !== undefined ? opt_this : this,
37547 node, value, objectStack);
37548 var parent = objectStack[objectStack.length - 1];
37549 var parentNode = parent.node;
37550 parentNode.appendChild(node);
37551 };
37552};
37553
37554
37555/**
37556 * Create a serializer that calls the provided `nodeWriter` from
37557 * {@link ol.xml.serialize}. This can be used by the parent writer to have the
37558 * 'nodeWriter' called with an array of values when the `nodeWriter` was
37559 * designed to serialize a single item. An example would be a LineString
37560 * geometry writer, which could be reused for writing MultiLineString
37561 * geometries.
37562 * @param {function(this: T, Node, V, Array.<*>)}
37563 * nodeWriter Node writer.
37564 * @param {T=} opt_this The object to use as `this` in `nodeWriter`.
37565 * @return {ol.XmlSerializer} Serializer.
37566 * @template T, V
37567 */
37568ol.xml.makeArraySerializer = function(nodeWriter, opt_this) {
37569 var serializersNS, nodeFactory;
37570 return function(node, value, objectStack) {
37571 if (serializersNS === undefined) {
37572 serializersNS = {};
37573 var serializers = {};
37574 serializers[node.localName] = nodeWriter;
37575 serializersNS[node.namespaceURI] = serializers;
37576 nodeFactory = ol.xml.makeSimpleNodeFactory(node.localName);
37577 }
37578 ol.xml.serialize(serializersNS, nodeFactory, value, objectStack);
37579 };
37580};
37581
37582
37583/**
37584 * Create a node factory which can use the `opt_keys` passed to
37585 * {@link ol.xml.serialize} or {@link ol.xml.pushSerializeAndPop} as node names,
37586 * or a fixed node name. The namespace of the created nodes can either be fixed,
37587 * or the parent namespace will be used.
37588 * @param {string=} opt_nodeName Fixed node name which will be used for all
37589 * created nodes. If not provided, the 3rd argument to the resulting node
37590 * factory needs to be provided and will be the nodeName.
37591 * @param {string=} opt_namespaceURI Fixed namespace URI which will be used for
37592 * all created nodes. If not provided, the namespace of the parent node will
37593 * be used.
37594 * @return {function(*, Array.<*>, string=): (Node|undefined)} Node factory.
37595 */
37596ol.xml.makeSimpleNodeFactory = function(opt_nodeName, opt_namespaceURI) {
37597 var fixedNodeName = opt_nodeName;
37598 return (
37599 /**
37600 * @param {*} value Value.
37601 * @param {Array.<*>} objectStack Object stack.
37602 * @param {string=} opt_nodeName Node name.
37603 * @return {Node} Node.
37604 */
37605 function(value, objectStack, opt_nodeName) {
37606 var context = objectStack[objectStack.length - 1];
37607 var node = context.node;
37608 var nodeName = fixedNodeName;
37609 if (nodeName === undefined) {
37610 nodeName = opt_nodeName;
37611 }
37612 var namespaceURI = opt_namespaceURI;
37613 if (opt_namespaceURI === undefined) {
37614 namespaceURI = node.namespaceURI;
37615 }
37616 return ol.xml.createElementNS(namespaceURI, /** @type {string} */ (nodeName));
37617 }
37618 );
37619};
37620
37621
37622/**
37623 * A node factory that creates a node using the parent's `namespaceURI` and the
37624 * `nodeName` passed by {@link ol.xml.serialize} or
37625 * {@link ol.xml.pushSerializeAndPop} to the node factory.
37626 * @const
37627 * @type {function(*, Array.<*>, string=): (Node|undefined)}
37628 */
37629ol.xml.OBJECT_PROPERTY_NODE_FACTORY = ol.xml.makeSimpleNodeFactory();
37630
37631
37632/**
37633 * Create an array of `values` to be used with {@link ol.xml.serialize} or
37634 * {@link ol.xml.pushSerializeAndPop}, where `orderedKeys` has to be provided as
37635 * `opt_key` argument.
37636 * @param {Object.<string, V>} object Key-value pairs for the sequence. Keys can
37637 * be a subset of the `orderedKeys`.
37638 * @param {Array.<string>} orderedKeys Keys in the order of the sequence.
37639 * @return {Array.<V>} Values in the order of the sequence. The resulting array
37640 * has the same length as the `orderedKeys` array. Values that are not
37641 * present in `object` will be `undefined` in the resulting array.
37642 * @template V
37643 */
37644ol.xml.makeSequence = function(object, orderedKeys) {
37645 var length = orderedKeys.length;
37646 var sequence = new Array(length);
37647 for (var i = 0; i < length; ++i) {
37648 sequence[i] = object[orderedKeys[i]];
37649 }
37650 return sequence;
37651};
37652
37653
37654/**
37655 * Create a namespaced structure, using the same values for each namespace.
37656 * This can be used as a starting point for versioned parsers, when only a few
37657 * values are version specific.
37658 * @param {Array.<string>} namespaceURIs Namespace URIs.
37659 * @param {T} structure Structure.
37660 * @param {Object.<string, T>=} opt_structureNS Namespaced structure to add to.
37661 * @return {Object.<string, T>} Namespaced structure.
37662 * @template T
37663 */
37664ol.xml.makeStructureNS = function(namespaceURIs, structure, opt_structureNS) {
37665 /**
37666 * @type {Object.<string, *>}
37667 */
37668 var structureNS = opt_structureNS !== undefined ? opt_structureNS : {};
37669 var i, ii;
37670 for (i = 0, ii = namespaceURIs.length; i < ii; ++i) {
37671 structureNS[namespaceURIs[i]] = structure;
37672 }
37673 return structureNS;
37674};
37675
37676
37677/**
37678 * Parse a node using the parsers and object stack.
37679 * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS
37680 * Parsers by namespace.
37681 * @param {Node} node Node.
37682 * @param {Array.<*>} objectStack Object stack.
37683 * @param {*=} opt_this The object to use as `this`.
37684 */
37685ol.xml.parseNode = function(parsersNS, node, objectStack, opt_this) {
37686 var n;
37687 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
37688 var parsers = parsersNS[n.namespaceURI];
37689 if (parsers !== undefined) {
37690 var parser = parsers[n.localName];
37691 if (parser !== undefined) {
37692 parser.call(opt_this, n, objectStack);
37693 }
37694 }
37695 }
37696};
37697
37698
37699/**
37700 * Push an object on top of the stack, parse and return the popped object.
37701 * @param {T} object Object.
37702 * @param {Object.<string, Object.<string, ol.XmlParser>>} parsersNS
37703 * Parsers by namespace.
37704 * @param {Node} node Node.
37705 * @param {Array.<*>} objectStack Object stack.
37706 * @param {*=} opt_this The object to use as `this`.
37707 * @return {T} Object.
37708 * @template T
37709 */
37710ol.xml.pushParseAndPop = function(
37711 object, parsersNS, node, objectStack, opt_this) {
37712 objectStack.push(object);
37713 ol.xml.parseNode(parsersNS, node, objectStack, opt_this);
37714 return objectStack.pop();
37715};
37716
37717
37718/**
37719 * Walk through an array of `values` and call a serializer for each value.
37720 * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS
37721 * Namespaced serializers.
37722 * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory
37723 * Node factory. The `nodeFactory` creates the node whose namespace and name
37724 * will be used to choose a node writer from `serializersNS`. This
37725 * separation allows us to decide what kind of node to create, depending on
37726 * the value we want to serialize. An example for this would be different
37727 * geometry writers based on the geometry type.
37728 * @param {Array.<*>} values Values to serialize. An example would be an array
37729 * of {@link ol.Feature} instances.
37730 * @param {Array.<*>} objectStack Node stack.
37731 * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the
37732 * `nodeFactory`. This is used for serializing object literals where the
37733 * node name relates to the property key. The array length of `opt_keys` has
37734 * to match the length of `values`. For serializing a sequence, `opt_keys`
37735 * determines the order of the sequence.
37736 * @param {T=} opt_this The object to use as `this` for the node factory and
37737 * serializers.
37738 * @template T
37739 */
37740ol.xml.serialize = function(
37741 serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {
37742 var length = (opt_keys !== undefined ? opt_keys : values).length;
37743 var value, node;
37744 for (var i = 0; i < length; ++i) {
37745 value = values[i];
37746 if (value !== undefined) {
37747 node = nodeFactory.call(opt_this, value, objectStack,
37748 opt_keys !== undefined ? opt_keys[i] : undefined);
37749 if (node !== undefined) {
37750 serializersNS[node.namespaceURI][node.localName]
37751 .call(opt_this, node, value, objectStack);
37752 }
37753 }
37754 }
37755};
37756
37757
37758/**
37759 * @param {O} object Object.
37760 * @param {Object.<string, Object.<string, ol.XmlSerializer>>} serializersNS
37761 * Namespaced serializers.
37762 * @param {function(this: T, *, Array.<*>, (string|undefined)): (Node|undefined)} nodeFactory
37763 * Node factory. The `nodeFactory` creates the node whose namespace and name
37764 * will be used to choose a node writer from `serializersNS`. This
37765 * separation allows us to decide what kind of node to create, depending on
37766 * the value we want to serialize. An example for this would be different
37767 * geometry writers based on the geometry type.
37768 * @param {Array.<*>} values Values to serialize. An example would be an array
37769 * of {@link ol.Feature} instances.
37770 * @param {Array.<*>} objectStack Node stack.
37771 * @param {Array.<string>=} opt_keys Keys of the `values`. Will be passed to the
37772 * `nodeFactory`. This is used for serializing object literals where the
37773 * node name relates to the property key. The array length of `opt_keys` has
37774 * to match the length of `values`. For serializing a sequence, `opt_keys`
37775 * determines the order of the sequence.
37776 * @param {T=} opt_this The object to use as `this` for the node factory and
37777 * serializers.
37778 * @return {O|undefined} Object.
37779 * @template O, T
37780 */
37781ol.xml.pushSerializeAndPop = function(object,
37782 serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this) {
37783 objectStack.push(object);
37784 ol.xml.serialize(
37785 serializersNS, nodeFactory, values, objectStack, opt_keys, opt_this);
37786 return objectStack.pop();
37787};
37788
37789goog.provide('ol.featureloader');
37790
37791goog.require('ol');
37792goog.require('ol.format.FormatType');
37793goog.require('ol.xml');
37794
37795
37796/**
37797 * @param {string|ol.FeatureUrlFunction} url Feature URL service.
37798 * @param {ol.format.Feature} format Feature format.
37799 * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection, ol.Extent)|function(this:ol.source.Vector, Array.<ol.Feature>)} success
37800 * Function called with the loaded features and optionally with the data
37801 * projection. Called with the vector tile or source as `this`.
37802 * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure
37803 * Function called when loading failed. Called with the vector tile or
37804 * source as `this`.
37805 * @return {ol.FeatureLoader} The feature loader.
37806 */
37807ol.featureloader.loadFeaturesXhr = function(url, format, success, failure) {
37808 return (
37809 /**
37810 * @param {ol.Extent} extent Extent.
37811 * @param {number} resolution Resolution.
37812 * @param {ol.proj.Projection} projection Projection.
37813 * @this {ol.source.Vector|ol.VectorTile}
37814 */
37815 function(extent, resolution, projection) {
37816 var xhr = new XMLHttpRequest();
37817 xhr.open('GET',
37818 typeof url === 'function' ? url(extent, resolution, projection) : url,
37819 true);
37820 if (format.getType() == ol.format.FormatType.ARRAY_BUFFER) {
37821 xhr.responseType = 'arraybuffer';
37822 }
37823 /**
37824 * @param {Event} event Event.
37825 * @private
37826 */
37827 xhr.onload = function(event) {
37828 // status will be 0 for file:// urls
37829 if (!xhr.status || xhr.status >= 200 && xhr.status < 300) {
37830 var type = format.getType();
37831 /** @type {Document|Node|Object|string|undefined} */
37832 var source;
37833 if (type == ol.format.FormatType.JSON ||
37834 type == ol.format.FormatType.TEXT) {
37835 source = xhr.responseText;
37836 } else if (type == ol.format.FormatType.XML) {
37837 source = xhr.responseXML;
37838 if (!source) {
37839 source = ol.xml.parse(xhr.responseText);
37840 }
37841 } else if (type == ol.format.FormatType.ARRAY_BUFFER) {
37842 source = /** @type {ArrayBuffer} */ (xhr.response);
37843 }
37844 if (source) {
37845 success.call(this, format.readFeatures(source,
37846 {featureProjection: projection}),
37847 format.readProjection(source), format.getLastExtent());
37848 } else {
37849 failure.call(this);
37850 }
37851 } else {
37852 failure.call(this);
37853 }
37854 }.bind(this);
37855 /**
37856 * @private
37857 */
37858 xhr.onerror = function() {
37859 failure.call(this);
37860 }.bind(this);
37861 xhr.send();
37862 });
37863};
37864
37865
37866/**
37867 * Create an XHR feature loader for a `url` and `format`. The feature loader
37868 * loads features (with XHR), parses the features, and adds them to the
37869 * vector source.
37870 * @param {string|ol.FeatureUrlFunction} url Feature URL service.
37871 * @param {ol.format.Feature} format Feature format.
37872 * @return {ol.FeatureLoader} The feature loader.
37873 * @api
37874 */
37875ol.featureloader.xhr = function(url, format) {
37876 return ol.featureloader.loadFeaturesXhr(url, format,
37877 /**
37878 * @param {Array.<ol.Feature>} features The loaded features.
37879 * @param {ol.proj.Projection} dataProjection Data projection.
37880 * @this {ol.source.Vector}
37881 */
37882 function(features, dataProjection) {
37883 this.addFeatures(features);
37884 }, /* FIXME handle error */ ol.nullFunction);
37885};
37886
37887goog.provide('ol.format.Feature');
37888
37889goog.require('ol.geom.Geometry');
37890goog.require('ol.obj');
37891goog.require('ol.proj');
37892
37893
37894/**
37895 * @classdesc
37896 * Abstract base class; normally only used for creating subclasses and not
37897 * instantiated in apps.
37898 * Base class for feature formats.
37899 * {ol.format.Feature} subclasses provide the ability to decode and encode
37900 * {@link ol.Feature} objects from a variety of commonly used geospatial
37901 * file formats. See the documentation for each format for more details.
37902 *
37903 * @constructor
37904 * @abstract
37905 * @api
37906 */
37907ol.format.Feature = function() {
37908
37909 /**
37910 * @protected
37911 * @type {ol.proj.Projection}
37912 */
37913 this.defaultDataProjection = null;
37914
37915 /**
37916 * @protected
37917 * @type {ol.proj.Projection}
37918 */
37919 this.defaultFeatureProjection = null;
37920
37921};
37922
37923
37924/**
37925 * Adds the data projection to the read options.
37926 * @param {Document|Node|Object|string} source Source.
37927 * @param {olx.format.ReadOptions=} opt_options Options.
37928 * @return {olx.format.ReadOptions|undefined} Options.
37929 * @protected
37930 */
37931ol.format.Feature.prototype.getReadOptions = function(source, opt_options) {
37932 var options;
37933 if (opt_options) {
37934 options = {
37935 dataProjection: opt_options.dataProjection ?
37936 opt_options.dataProjection : this.readProjection(source),
37937 featureProjection: opt_options.featureProjection
37938 };
37939 }
37940 return this.adaptOptions(options);
37941};
37942
37943
37944/**
37945 * Sets the `defaultDataProjection` on the options, if no `dataProjection`
37946 * is set.
37947 * @param {olx.format.WriteOptions|olx.format.ReadOptions|undefined} options
37948 * Options.
37949 * @protected
37950 * @return {olx.format.WriteOptions|olx.format.ReadOptions|undefined}
37951 * Updated options.
37952 */
37953ol.format.Feature.prototype.adaptOptions = function(options) {
37954 return ol.obj.assign({
37955 dataProjection: this.defaultDataProjection,
37956 featureProjection: this.defaultFeatureProjection
37957 }, options);
37958};
37959
37960
37961/**
37962 * Get the extent from the source of the last {@link readFeatures} call.
37963 * @return {ol.Extent} Tile extent.
37964 */
37965ol.format.Feature.prototype.getLastExtent = function() {
37966 return null;
37967};
37968
37969
37970/**
37971 * @abstract
37972 * @return {ol.format.FormatType} Format.
37973 */
37974ol.format.Feature.prototype.getType = function() {};
37975
37976
37977/**
37978 * Read a single feature from a source.
37979 *
37980 * @abstract
37981 * @param {Document|Node|Object|string} source Source.
37982 * @param {olx.format.ReadOptions=} opt_options Read options.
37983 * @return {ol.Feature} Feature.
37984 */
37985ol.format.Feature.prototype.readFeature = function(source, opt_options) {};
37986
37987
37988/**
37989 * Read all features from a source.
37990 *
37991 * @abstract
37992 * @param {Document|Node|ArrayBuffer|Object|string} source Source.
37993 * @param {olx.format.ReadOptions=} opt_options Read options.
37994 * @return {Array.<ol.Feature>} Features.
37995 */
37996ol.format.Feature.prototype.readFeatures = function(source, opt_options) {};
37997
37998
37999/**
38000 * Read a single geometry from a source.
38001 *
38002 * @abstract
38003 * @param {Document|Node|Object|string} source Source.
38004 * @param {olx.format.ReadOptions=} opt_options Read options.
38005 * @return {ol.geom.Geometry} Geometry.
38006 */
38007ol.format.Feature.prototype.readGeometry = function(source, opt_options) {};
38008
38009
38010/**
38011 * Read the projection from a source.
38012 *
38013 * @abstract
38014 * @param {Document|Node|Object|string} source Source.
38015 * @return {ol.proj.Projection} Projection.
38016 */
38017ol.format.Feature.prototype.readProjection = function(source) {};
38018
38019
38020/**
38021 * Encode a feature in this format.
38022 *
38023 * @abstract
38024 * @param {ol.Feature} feature Feature.
38025 * @param {olx.format.WriteOptions=} opt_options Write options.
38026 * @return {string} Result.
38027 */
38028ol.format.Feature.prototype.writeFeature = function(feature, opt_options) {};
38029
38030
38031/**
38032 * Encode an array of features in this format.
38033 *
38034 * @abstract
38035 * @param {Array.<ol.Feature>} features Features.
38036 * @param {olx.format.WriteOptions=} opt_options Write options.
38037 * @return {string} Result.
38038 */
38039ol.format.Feature.prototype.writeFeatures = function(features, opt_options) {};
38040
38041
38042/**
38043 * Write a single geometry in this format.
38044 *
38045 * @abstract
38046 * @param {ol.geom.Geometry} geometry Geometry.
38047 * @param {olx.format.WriteOptions=} opt_options Write options.
38048 * @return {string} Result.
38049 */
38050ol.format.Feature.prototype.writeGeometry = function(geometry, opt_options) {};
38051
38052
38053/**
38054 * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
38055 * @param {boolean} write Set to true for writing, false for reading.
38056 * @param {(olx.format.WriteOptions|olx.format.ReadOptions)=} opt_options
38057 * Options.
38058 * @return {ol.geom.Geometry|ol.Extent} Transformed geometry.
38059 * @protected
38060 */
38061ol.format.Feature.transformWithOptions = function(
38062 geometry, write, opt_options) {
38063 var featureProjection = opt_options ?
38064 ol.proj.get(opt_options.featureProjection) : null;
38065 var dataProjection = opt_options ?
38066 ol.proj.get(opt_options.dataProjection) : null;
38067 /**
38068 * @type {ol.geom.Geometry|ol.Extent}
38069 */
38070 var transformed;
38071 if (featureProjection && dataProjection &&
38072 !ol.proj.equivalent(featureProjection, dataProjection)) {
38073 if (geometry instanceof ol.geom.Geometry) {
38074 transformed = (write ? geometry.clone() : geometry).transform(
38075 write ? featureProjection : dataProjection,
38076 write ? dataProjection : featureProjection);
38077 } else {
38078 // FIXME this is necessary because ol.format.GML treats extents
38079 // as geometries
38080 transformed = ol.proj.transformExtent(
38081 geometry,
38082 dataProjection,
38083 featureProjection);
38084 }
38085 } else {
38086 transformed = geometry;
38087 }
38088 if (write && opt_options && opt_options.decimals !== undefined) {
38089 var power = Math.pow(10, opt_options.decimals);
38090 // if decimals option on write, round each coordinate appropriately
38091 /**
38092 * @param {Array.<number>} coordinates Coordinates.
38093 * @return {Array.<number>} Transformed coordinates.
38094 */
38095 var transform = function(coordinates) {
38096 for (var i = 0, ii = coordinates.length; i < ii; ++i) {
38097 coordinates[i] = Math.round(coordinates[i] * power) / power;
38098 }
38099 return coordinates;
38100 };
38101 if (transformed === geometry) {
38102 transformed = transformed.clone();
38103 }
38104 transformed.applyTransform(transform);
38105 }
38106 return transformed;
38107};
38108
38109goog.provide('ol.format.JSONFeature');
38110
38111goog.require('ol');
38112goog.require('ol.format.Feature');
38113goog.require('ol.format.FormatType');
38114
38115
38116/**
38117 * @classdesc
38118 * Abstract base class; normally only used for creating subclasses and not
38119 * instantiated in apps.
38120 * Base class for JSON feature formats.
38121 *
38122 * @constructor
38123 * @abstract
38124 * @extends {ol.format.Feature}
38125 */
38126ol.format.JSONFeature = function() {
38127 ol.format.Feature.call(this);
38128};
38129ol.inherits(ol.format.JSONFeature, ol.format.Feature);
38130
38131
38132/**
38133 * @param {Document|Node|Object|string} source Source.
38134 * @private
38135 * @return {Object} Object.
38136 */
38137ol.format.JSONFeature.prototype.getObject_ = function(source) {
38138 if (typeof source === 'string') {
38139 var object = JSON.parse(source);
38140 return object ? /** @type {Object} */ (object) : null;
38141 } else if (source !== null) {
38142 return source;
38143 } else {
38144 return null;
38145 }
38146};
38147
38148
38149/**
38150 * @inheritDoc
38151 */
38152ol.format.JSONFeature.prototype.getType = function() {
38153 return ol.format.FormatType.JSON;
38154};
38155
38156
38157/**
38158 * @inheritDoc
38159 */
38160ol.format.JSONFeature.prototype.readFeature = function(source, opt_options) {
38161 return this.readFeatureFromObject(
38162 this.getObject_(source), this.getReadOptions(source, opt_options));
38163};
38164
38165
38166/**
38167 * @inheritDoc
38168 */
38169ol.format.JSONFeature.prototype.readFeatures = function(source, opt_options) {
38170 return this.readFeaturesFromObject(
38171 this.getObject_(source), this.getReadOptions(source, opt_options));
38172};
38173
38174
38175/**
38176 * @abstract
38177 * @param {Object} object Object.
38178 * @param {olx.format.ReadOptions=} opt_options Read options.
38179 * @protected
38180 * @return {ol.Feature} Feature.
38181 */
38182ol.format.JSONFeature.prototype.readFeatureFromObject = function(object, opt_options) {};
38183
38184
38185/**
38186 * @abstract
38187 * @param {Object} object Object.
38188 * @param {olx.format.ReadOptions=} opt_options Read options.
38189 * @protected
38190 * @return {Array.<ol.Feature>} Features.
38191 */
38192ol.format.JSONFeature.prototype.readFeaturesFromObject = function(object, opt_options) {};
38193
38194
38195/**
38196 * @inheritDoc
38197 */
38198ol.format.JSONFeature.prototype.readGeometry = function(source, opt_options) {
38199 return this.readGeometryFromObject(
38200 this.getObject_(source), this.getReadOptions(source, opt_options));
38201};
38202
38203
38204/**
38205 * @abstract
38206 * @param {Object} object Object.
38207 * @param {olx.format.ReadOptions=} opt_options Read options.
38208 * @protected
38209 * @return {ol.geom.Geometry} Geometry.
38210 */
38211ol.format.JSONFeature.prototype.readGeometryFromObject = function(object, opt_options) {};
38212
38213
38214/**
38215 * @inheritDoc
38216 */
38217ol.format.JSONFeature.prototype.readProjection = function(source) {
38218 return this.readProjectionFromObject(this.getObject_(source));
38219};
38220
38221
38222/**
38223 * @abstract
38224 * @param {Object} object Object.
38225 * @protected
38226 * @return {ol.proj.Projection} Projection.
38227 */
38228ol.format.JSONFeature.prototype.readProjectionFromObject = function(object) {};
38229
38230
38231/**
38232 * @inheritDoc
38233 */
38234ol.format.JSONFeature.prototype.writeFeature = function(feature, opt_options) {
38235 return JSON.stringify(this.writeFeatureObject(feature, opt_options));
38236};
38237
38238
38239/**
38240 * @abstract
38241 * @param {ol.Feature} feature Feature.
38242 * @param {olx.format.WriteOptions=} opt_options Write options.
38243 * @return {Object} Object.
38244 */
38245ol.format.JSONFeature.prototype.writeFeatureObject = function(feature, opt_options) {};
38246
38247
38248/**
38249 * @inheritDoc
38250 */
38251ol.format.JSONFeature.prototype.writeFeatures = function(features, opt_options) {
38252 return JSON.stringify(this.writeFeaturesObject(features, opt_options));
38253};
38254
38255
38256/**
38257 * @abstract
38258 * @param {Array.<ol.Feature>} features Features.
38259 * @param {olx.format.WriteOptions=} opt_options Write options.
38260 * @return {Object} Object.
38261 */
38262ol.format.JSONFeature.prototype.writeFeaturesObject = function(features, opt_options) {};
38263
38264
38265/**
38266 * @inheritDoc
38267 */
38268ol.format.JSONFeature.prototype.writeGeometry = function(geometry, opt_options) {
38269 return JSON.stringify(this.writeGeometryObject(geometry, opt_options));
38270};
38271
38272
38273/**
38274 * @abstract
38275 * @param {ol.geom.Geometry} geometry Geometry.
38276 * @param {olx.format.WriteOptions=} opt_options Write options.
38277 * @return {Object} Object.
38278 */
38279ol.format.JSONFeature.prototype.writeGeometryObject = function(geometry, opt_options) {};
38280
38281goog.provide('ol.geom.flat.interpolate');
38282
38283goog.require('ol.array');
38284goog.require('ol.math');
38285
38286
38287/**
38288 * @param {Array.<number>} flatCoordinates Flat coordinates.
38289 * @param {number} offset Offset.
38290 * @param {number} end End.
38291 * @param {number} stride Stride.
38292 * @param {number} fraction Fraction.
38293 * @param {Array.<number>=} opt_dest Destination.
38294 * @return {Array.<number>} Destination.
38295 */
38296ol.geom.flat.interpolate.lineString = function(flatCoordinates, offset, end, stride, fraction, opt_dest) {
38297 var pointX = NaN;
38298 var pointY = NaN;
38299 var n = (end - offset) / stride;
38300 if (n === 1) {
38301 pointX = flatCoordinates[offset];
38302 pointY = flatCoordinates[offset + 1];
38303 } else if (n == 2) {
38304 pointX = (1 - fraction) * flatCoordinates[offset] +
38305 fraction * flatCoordinates[offset + stride];
38306 pointY = (1 - fraction) * flatCoordinates[offset + 1] +
38307 fraction * flatCoordinates[offset + stride + 1];
38308 } else if (n !== 0) {
38309 var x1 = flatCoordinates[offset];
38310 var y1 = flatCoordinates[offset + 1];
38311 var length = 0;
38312 var cumulativeLengths = [0];
38313 var i;
38314 for (i = offset + stride; i < end; i += stride) {
38315 var x2 = flatCoordinates[i];
38316 var y2 = flatCoordinates[i + 1];
38317 length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
38318 cumulativeLengths.push(length);
38319 x1 = x2;
38320 y1 = y2;
38321 }
38322 var target = fraction * length;
38323 var index = ol.array.binarySearch(cumulativeLengths, target);
38324 if (index < 0) {
38325 var t = (target - cumulativeLengths[-index - 2]) /
38326 (cumulativeLengths[-index - 1] - cumulativeLengths[-index - 2]);
38327 var o = offset + (-index - 2) * stride;
38328 pointX = ol.math.lerp(
38329 flatCoordinates[o], flatCoordinates[o + stride], t);
38330 pointY = ol.math.lerp(
38331 flatCoordinates[o + 1], flatCoordinates[o + stride + 1], t);
38332 } else {
38333 pointX = flatCoordinates[offset + index * stride];
38334 pointY = flatCoordinates[offset + index * stride + 1];
38335 }
38336 }
38337 if (opt_dest) {
38338 opt_dest[0] = pointX;
38339 opt_dest[1] = pointY;
38340 return opt_dest;
38341 } else {
38342 return [pointX, pointY];
38343 }
38344};
38345
38346
38347/**
38348 * @param {Array.<number>} flatCoordinates Flat coordinates.
38349 * @param {number} offset Offset.
38350 * @param {number} end End.
38351 * @param {number} stride Stride.
38352 * @param {number} m M.
38353 * @param {boolean} extrapolate Extrapolate.
38354 * @return {ol.Coordinate} Coordinate.
38355 */
38356ol.geom.flat.interpolate.lineStringCoordinateAtM = function(flatCoordinates, offset, end, stride, m, extrapolate) {
38357 if (end == offset) {
38358 return null;
38359 }
38360 var coordinate;
38361 if (m < flatCoordinates[offset + stride - 1]) {
38362 if (extrapolate) {
38363 coordinate = flatCoordinates.slice(offset, offset + stride);
38364 coordinate[stride - 1] = m;
38365 return coordinate;
38366 } else {
38367 return null;
38368 }
38369 } else if (flatCoordinates[end - 1] < m) {
38370 if (extrapolate) {
38371 coordinate = flatCoordinates.slice(end - stride, end);
38372 coordinate[stride - 1] = m;
38373 return coordinate;
38374 } else {
38375 return null;
38376 }
38377 }
38378 // FIXME use O(1) search
38379 if (m == flatCoordinates[offset + stride - 1]) {
38380 return flatCoordinates.slice(offset, offset + stride);
38381 }
38382 var lo = offset / stride;
38383 var hi = end / stride;
38384 while (lo < hi) {
38385 var mid = (lo + hi) >> 1;
38386 if (m < flatCoordinates[(mid + 1) * stride - 1]) {
38387 hi = mid;
38388 } else {
38389 lo = mid + 1;
38390 }
38391 }
38392 var m0 = flatCoordinates[lo * stride - 1];
38393 if (m == m0) {
38394 return flatCoordinates.slice((lo - 1) * stride, (lo - 1) * stride + stride);
38395 }
38396 var m1 = flatCoordinates[(lo + 1) * stride - 1];
38397 var t = (m - m0) / (m1 - m0);
38398 coordinate = [];
38399 var i;
38400 for (i = 0; i < stride - 1; ++i) {
38401 coordinate.push(ol.math.lerp(flatCoordinates[(lo - 1) * stride + i],
38402 flatCoordinates[lo * stride + i], t));
38403 }
38404 coordinate.push(m);
38405 return coordinate;
38406};
38407
38408
38409/**
38410 * @param {Array.<number>} flatCoordinates Flat coordinates.
38411 * @param {number} offset Offset.
38412 * @param {Array.<number>} ends Ends.
38413 * @param {number} stride Stride.
38414 * @param {number} m M.
38415 * @param {boolean} extrapolate Extrapolate.
38416 * @param {boolean} interpolate Interpolate.
38417 * @return {ol.Coordinate} Coordinate.
38418 */
38419ol.geom.flat.interpolate.lineStringsCoordinateAtM = function(
38420 flatCoordinates, offset, ends, stride, m, extrapolate, interpolate) {
38421 if (interpolate) {
38422 return ol.geom.flat.interpolate.lineStringCoordinateAtM(
38423 flatCoordinates, offset, ends[ends.length - 1], stride, m, extrapolate);
38424 }
38425 var coordinate;
38426 if (m < flatCoordinates[stride - 1]) {
38427 if (extrapolate) {
38428 coordinate = flatCoordinates.slice(0, stride);
38429 coordinate[stride - 1] = m;
38430 return coordinate;
38431 } else {
38432 return null;
38433 }
38434 }
38435 if (flatCoordinates[flatCoordinates.length - 1] < m) {
38436 if (extrapolate) {
38437 coordinate = flatCoordinates.slice(flatCoordinates.length - stride);
38438 coordinate[stride - 1] = m;
38439 return coordinate;
38440 } else {
38441 return null;
38442 }
38443 }
38444 var i, ii;
38445 for (i = 0, ii = ends.length; i < ii; ++i) {
38446 var end = ends[i];
38447 if (offset == end) {
38448 continue;
38449 }
38450 if (m < flatCoordinates[offset + stride - 1]) {
38451 return null;
38452 } else if (m <= flatCoordinates[end - 1]) {
38453 return ol.geom.flat.interpolate.lineStringCoordinateAtM(
38454 flatCoordinates, offset, end, stride, m, false);
38455 }
38456 offset = end;
38457 }
38458 return null;
38459};
38460
38461goog.provide('ol.geom.flat.length');
38462
38463
38464/**
38465 * @param {Array.<number>} flatCoordinates Flat coordinates.
38466 * @param {number} offset Offset.
38467 * @param {number} end End.
38468 * @param {number} stride Stride.
38469 * @return {number} Length.
38470 */
38471ol.geom.flat.length.lineString = function(flatCoordinates, offset, end, stride) {
38472 var x1 = flatCoordinates[offset];
38473 var y1 = flatCoordinates[offset + 1];
38474 var length = 0;
38475 var i;
38476 for (i = offset + stride; i < end; i += stride) {
38477 var x2 = flatCoordinates[i];
38478 var y2 = flatCoordinates[i + 1];
38479 length += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
38480 x1 = x2;
38481 y1 = y2;
38482 }
38483 return length;
38484};
38485
38486
38487/**
38488 * @param {Array.<number>} flatCoordinates Flat coordinates.
38489 * @param {number} offset Offset.
38490 * @param {number} end End.
38491 * @param {number} stride Stride.
38492 * @return {number} Perimeter.
38493 */
38494ol.geom.flat.length.linearRing = function(flatCoordinates, offset, end, stride) {
38495 var perimeter =
38496 ol.geom.flat.length.lineString(flatCoordinates, offset, end, stride);
38497 var dx = flatCoordinates[end - stride] - flatCoordinates[offset];
38498 var dy = flatCoordinates[end - stride + 1] - flatCoordinates[offset + 1];
38499 perimeter += Math.sqrt(dx * dx + dy * dy);
38500 return perimeter;
38501};
38502
38503goog.provide('ol.geom.LineString');
38504
38505goog.require('ol');
38506goog.require('ol.array');
38507goog.require('ol.extent');
38508goog.require('ol.geom.GeometryLayout');
38509goog.require('ol.geom.GeometryType');
38510goog.require('ol.geom.SimpleGeometry');
38511goog.require('ol.geom.flat.closest');
38512goog.require('ol.geom.flat.deflate');
38513goog.require('ol.geom.flat.inflate');
38514goog.require('ol.geom.flat.interpolate');
38515goog.require('ol.geom.flat.intersectsextent');
38516goog.require('ol.geom.flat.length');
38517goog.require('ol.geom.flat.segments');
38518goog.require('ol.geom.flat.simplify');
38519
38520
38521/**
38522 * @classdesc
38523 * Linestring geometry.
38524 *
38525 * @constructor
38526 * @extends {ol.geom.SimpleGeometry}
38527 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
38528 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
38529 * @api
38530 */
38531ol.geom.LineString = function(coordinates, opt_layout) {
38532
38533 ol.geom.SimpleGeometry.call(this);
38534
38535 /**
38536 * @private
38537 * @type {ol.Coordinate}
38538 */
38539 this.flatMidpoint_ = null;
38540
38541 /**
38542 * @private
38543 * @type {number}
38544 */
38545 this.flatMidpointRevision_ = -1;
38546
38547 /**
38548 * @private
38549 * @type {number}
38550 */
38551 this.maxDelta_ = -1;
38552
38553 /**
38554 * @private
38555 * @type {number}
38556 */
38557 this.maxDeltaRevision_ = -1;
38558
38559 this.setCoordinates(coordinates, opt_layout);
38560
38561};
38562ol.inherits(ol.geom.LineString, ol.geom.SimpleGeometry);
38563
38564
38565/**
38566 * Append the passed coordinate to the coordinates of the linestring.
38567 * @param {ol.Coordinate} coordinate Coordinate.
38568 * @api
38569 */
38570ol.geom.LineString.prototype.appendCoordinate = function(coordinate) {
38571 if (!this.flatCoordinates) {
38572 this.flatCoordinates = coordinate.slice();
38573 } else {
38574 ol.array.extend(this.flatCoordinates, coordinate);
38575 }
38576 this.changed();
38577};
38578
38579
38580/**
38581 * Make a complete copy of the geometry.
38582 * @return {!ol.geom.LineString} Clone.
38583 * @override
38584 * @api
38585 */
38586ol.geom.LineString.prototype.clone = function() {
38587 var lineString = new ol.geom.LineString(null);
38588 lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
38589 return lineString;
38590};
38591
38592
38593/**
38594 * @inheritDoc
38595 */
38596ol.geom.LineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
38597 if (minSquaredDistance <
38598 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
38599 return minSquaredDistance;
38600 }
38601 if (this.maxDeltaRevision_ != this.getRevision()) {
38602 this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getMaxSquaredDelta(
38603 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride, 0));
38604 this.maxDeltaRevision_ = this.getRevision();
38605 }
38606 return ol.geom.flat.closest.getClosestPoint(
38607 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
38608 this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
38609};
38610
38611
38612/**
38613 * Iterate over each segment, calling the provided callback.
38614 * If the callback returns a truthy value the function returns that
38615 * value immediately. Otherwise the function returns `false`.
38616 *
38617 * @param {function(this: S, ol.Coordinate, ol.Coordinate): T} callback Function
38618 * called for each segment.
38619 * @param {S=} opt_this The object to be used as the value of 'this'
38620 * within callback.
38621 * @return {T|boolean} Value.
38622 * @template T,S
38623 * @api
38624 */
38625ol.geom.LineString.prototype.forEachSegment = function(callback, opt_this) {
38626 return ol.geom.flat.segments.forEach(this.flatCoordinates, 0,
38627 this.flatCoordinates.length, this.stride, callback, opt_this);
38628};
38629
38630
38631/**
38632 * Returns the coordinate at `m` using linear interpolation, or `null` if no
38633 * such coordinate exists.
38634 *
38635 * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
38636 * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
38637 * M will return the first coordinate and Ms greater than the last M will
38638 * return the last coordinate.
38639 *
38640 * @param {number} m M.
38641 * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
38642 * @return {ol.Coordinate} Coordinate.
38643 * @api
38644 */
38645ol.geom.LineString.prototype.getCoordinateAtM = function(m, opt_extrapolate) {
38646 if (this.layout != ol.geom.GeometryLayout.XYM &&
38647 this.layout != ol.geom.GeometryLayout.XYZM) {
38648 return null;
38649 }
38650 var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
38651 return ol.geom.flat.interpolate.lineStringCoordinateAtM(this.flatCoordinates, 0,
38652 this.flatCoordinates.length, this.stride, m, extrapolate);
38653};
38654
38655
38656/**
38657 * Return the coordinates of the linestring.
38658 * @return {Array.<ol.Coordinate>} Coordinates.
38659 * @override
38660 * @api
38661 */
38662ol.geom.LineString.prototype.getCoordinates = function() {
38663 return ol.geom.flat.inflate.coordinates(
38664 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
38665};
38666
38667
38668/**
38669 * Return the coordinate at the provided fraction along the linestring.
38670 * The `fraction` is a number between 0 and 1, where 0 is the start of the
38671 * linestring and 1 is the end.
38672 * @param {number} fraction Fraction.
38673 * @param {ol.Coordinate=} opt_dest Optional coordinate whose values will
38674 * be modified. If not provided, a new coordinate will be returned.
38675 * @return {ol.Coordinate} Coordinate of the interpolated point.
38676 * @api
38677 */
38678ol.geom.LineString.prototype.getCoordinateAt = function(fraction, opt_dest) {
38679 return ol.geom.flat.interpolate.lineString(
38680 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
38681 fraction, opt_dest);
38682};
38683
38684
38685/**
38686 * Return the length of the linestring on projected plane.
38687 * @return {number} Length (on projected plane).
38688 * @api
38689 */
38690ol.geom.LineString.prototype.getLength = function() {
38691 return ol.geom.flat.length.lineString(
38692 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
38693};
38694
38695
38696/**
38697 * @return {Array.<number>} Flat midpoint.
38698 */
38699ol.geom.LineString.prototype.getFlatMidpoint = function() {
38700 if (this.flatMidpointRevision_ != this.getRevision()) {
38701 this.flatMidpoint_ = this.getCoordinateAt(0.5, this.flatMidpoint_);
38702 this.flatMidpointRevision_ = this.getRevision();
38703 }
38704 return this.flatMidpoint_;
38705};
38706
38707
38708/**
38709 * @inheritDoc
38710 */
38711ol.geom.LineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
38712 var simplifiedFlatCoordinates = [];
38713 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeucker(
38714 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
38715 squaredTolerance, simplifiedFlatCoordinates, 0);
38716 var simplifiedLineString = new ol.geom.LineString(null);
38717 simplifiedLineString.setFlatCoordinates(
38718 ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates);
38719 return simplifiedLineString;
38720};
38721
38722
38723/**
38724 * @inheritDoc
38725 * @api
38726 */
38727ol.geom.LineString.prototype.getType = function() {
38728 return ol.geom.GeometryType.LINE_STRING;
38729};
38730
38731
38732/**
38733 * @inheritDoc
38734 * @api
38735 */
38736ol.geom.LineString.prototype.intersectsExtent = function(extent) {
38737 return ol.geom.flat.intersectsextent.lineString(
38738 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride,
38739 extent);
38740};
38741
38742
38743/**
38744 * Set the coordinates of the linestring.
38745 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
38746 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
38747 * @override
38748 * @api
38749 */
38750ol.geom.LineString.prototype.setCoordinates = function(coordinates, opt_layout) {
38751 if (!coordinates) {
38752 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
38753 } else {
38754 this.setLayout(opt_layout, coordinates, 1);
38755 if (!this.flatCoordinates) {
38756 this.flatCoordinates = [];
38757 }
38758 this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
38759 this.flatCoordinates, 0, coordinates, this.stride);
38760 this.changed();
38761 }
38762};
38763
38764
38765/**
38766 * @param {ol.geom.GeometryLayout} layout Layout.
38767 * @param {Array.<number>} flatCoordinates Flat coordinates.
38768 */
38769ol.geom.LineString.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
38770 this.setFlatCoordinatesInternal(layout, flatCoordinates);
38771 this.changed();
38772};
38773
38774goog.provide('ol.geom.MultiLineString');
38775
38776goog.require('ol');
38777goog.require('ol.array');
38778goog.require('ol.extent');
38779goog.require('ol.geom.GeometryLayout');
38780goog.require('ol.geom.GeometryType');
38781goog.require('ol.geom.LineString');
38782goog.require('ol.geom.SimpleGeometry');
38783goog.require('ol.geom.flat.closest');
38784goog.require('ol.geom.flat.deflate');
38785goog.require('ol.geom.flat.inflate');
38786goog.require('ol.geom.flat.interpolate');
38787goog.require('ol.geom.flat.intersectsextent');
38788goog.require('ol.geom.flat.simplify');
38789
38790
38791/**
38792 * @classdesc
38793 * Multi-linestring geometry.
38794 *
38795 * @constructor
38796 * @extends {ol.geom.SimpleGeometry}
38797 * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
38798 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
38799 * @api
38800 */
38801ol.geom.MultiLineString = function(coordinates, opt_layout) {
38802
38803 ol.geom.SimpleGeometry.call(this);
38804
38805 /**
38806 * @type {Array.<number>}
38807 * @private
38808 */
38809 this.ends_ = [];
38810
38811 /**
38812 * @private
38813 * @type {number}
38814 */
38815 this.maxDelta_ = -1;
38816
38817 /**
38818 * @private
38819 * @type {number}
38820 */
38821 this.maxDeltaRevision_ = -1;
38822
38823 this.setCoordinates(coordinates, opt_layout);
38824
38825};
38826ol.inherits(ol.geom.MultiLineString, ol.geom.SimpleGeometry);
38827
38828
38829/**
38830 * Append the passed linestring to the multilinestring.
38831 * @param {ol.geom.LineString} lineString LineString.
38832 * @api
38833 */
38834ol.geom.MultiLineString.prototype.appendLineString = function(lineString) {
38835 if (!this.flatCoordinates) {
38836 this.flatCoordinates = lineString.getFlatCoordinates().slice();
38837 } else {
38838 ol.array.extend(
38839 this.flatCoordinates, lineString.getFlatCoordinates().slice());
38840 }
38841 this.ends_.push(this.flatCoordinates.length);
38842 this.changed();
38843};
38844
38845
38846/**
38847 * Make a complete copy of the geometry.
38848 * @return {!ol.geom.MultiLineString} Clone.
38849 * @override
38850 * @api
38851 */
38852ol.geom.MultiLineString.prototype.clone = function() {
38853 var multiLineString = new ol.geom.MultiLineString(null);
38854 multiLineString.setFlatCoordinates(
38855 this.layout, this.flatCoordinates.slice(), this.ends_.slice());
38856 return multiLineString;
38857};
38858
38859
38860/**
38861 * @inheritDoc
38862 */
38863ol.geom.MultiLineString.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
38864 if (minSquaredDistance <
38865 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
38866 return minSquaredDistance;
38867 }
38868 if (this.maxDeltaRevision_ != this.getRevision()) {
38869 this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getsMaxSquaredDelta(
38870 this.flatCoordinates, 0, this.ends_, this.stride, 0));
38871 this.maxDeltaRevision_ = this.getRevision();
38872 }
38873 return ol.geom.flat.closest.getsClosestPoint(
38874 this.flatCoordinates, 0, this.ends_, this.stride,
38875 this.maxDelta_, false, x, y, closestPoint, minSquaredDistance);
38876};
38877
38878
38879/**
38880 * Returns the coordinate at `m` using linear interpolation, or `null` if no
38881 * such coordinate exists.
38882 *
38883 * `opt_extrapolate` controls extrapolation beyond the range of Ms in the
38884 * MultiLineString. If `opt_extrapolate` is `true` then Ms less than the first
38885 * M will return the first coordinate and Ms greater than the last M will
38886 * return the last coordinate.
38887 *
38888 * `opt_interpolate` controls interpolation between consecutive LineStrings
38889 * within the MultiLineString. If `opt_interpolate` is `true` the coordinates
38890 * will be linearly interpolated between the last coordinate of one LineString
38891 * and the first coordinate of the next LineString. If `opt_interpolate` is
38892 * `false` then the function will return `null` for Ms falling between
38893 * LineStrings.
38894 *
38895 * @param {number} m M.
38896 * @param {boolean=} opt_extrapolate Extrapolate. Default is `false`.
38897 * @param {boolean=} opt_interpolate Interpolate. Default is `false`.
38898 * @return {ol.Coordinate} Coordinate.
38899 * @api
38900 */
38901ol.geom.MultiLineString.prototype.getCoordinateAtM = function(m, opt_extrapolate, opt_interpolate) {
38902 if ((this.layout != ol.geom.GeometryLayout.XYM &&
38903 this.layout != ol.geom.GeometryLayout.XYZM) ||
38904 this.flatCoordinates.length === 0) {
38905 return null;
38906 }
38907 var extrapolate = opt_extrapolate !== undefined ? opt_extrapolate : false;
38908 var interpolate = opt_interpolate !== undefined ? opt_interpolate : false;
38909 return ol.geom.flat.interpolate.lineStringsCoordinateAtM(this.flatCoordinates, 0,
38910 this.ends_, this.stride, m, extrapolate, interpolate);
38911};
38912
38913
38914/**
38915 * Return the coordinates of the multilinestring.
38916 * @return {Array.<Array.<ol.Coordinate>>} Coordinates.
38917 * @override
38918 * @api
38919 */
38920ol.geom.MultiLineString.prototype.getCoordinates = function() {
38921 return ol.geom.flat.inflate.coordinatess(
38922 this.flatCoordinates, 0, this.ends_, this.stride);
38923};
38924
38925
38926/**
38927 * @return {Array.<number>} Ends.
38928 */
38929ol.geom.MultiLineString.prototype.getEnds = function() {
38930 return this.ends_;
38931};
38932
38933
38934/**
38935 * Return the linestring at the specified index.
38936 * @param {number} index Index.
38937 * @return {ol.geom.LineString} LineString.
38938 * @api
38939 */
38940ol.geom.MultiLineString.prototype.getLineString = function(index) {
38941 if (index < 0 || this.ends_.length <= index) {
38942 return null;
38943 }
38944 var lineString = new ol.geom.LineString(null);
38945 lineString.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
38946 index === 0 ? 0 : this.ends_[index - 1], this.ends_[index]));
38947 return lineString;
38948};
38949
38950
38951/**
38952 * Return the linestrings of this multilinestring.
38953 * @return {Array.<ol.geom.LineString>} LineStrings.
38954 * @api
38955 */
38956ol.geom.MultiLineString.prototype.getLineStrings = function() {
38957 var flatCoordinates = this.flatCoordinates;
38958 var ends = this.ends_;
38959 var layout = this.layout;
38960 /** @type {Array.<ol.geom.LineString>} */
38961 var lineStrings = [];
38962 var offset = 0;
38963 var i, ii;
38964 for (i = 0, ii = ends.length; i < ii; ++i) {
38965 var end = ends[i];
38966 var lineString = new ol.geom.LineString(null);
38967 lineString.setFlatCoordinates(layout, flatCoordinates.slice(offset, end));
38968 lineStrings.push(lineString);
38969 offset = end;
38970 }
38971 return lineStrings;
38972};
38973
38974
38975/**
38976 * @return {Array.<number>} Flat midpoints.
38977 */
38978ol.geom.MultiLineString.prototype.getFlatMidpoints = function() {
38979 var midpoints = [];
38980 var flatCoordinates = this.flatCoordinates;
38981 var offset = 0;
38982 var ends = this.ends_;
38983 var stride = this.stride;
38984 var i, ii;
38985 for (i = 0, ii = ends.length; i < ii; ++i) {
38986 var end = ends[i];
38987 var midpoint = ol.geom.flat.interpolate.lineString(
38988 flatCoordinates, offset, end, stride, 0.5);
38989 ol.array.extend(midpoints, midpoint);
38990 offset = end;
38991 }
38992 return midpoints;
38993};
38994
38995
38996/**
38997 * @inheritDoc
38998 */
38999ol.geom.MultiLineString.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
39000 var simplifiedFlatCoordinates = [];
39001 var simplifiedEnds = [];
39002 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.douglasPeuckers(
39003 this.flatCoordinates, 0, this.ends_, this.stride, squaredTolerance,
39004 simplifiedFlatCoordinates, 0, simplifiedEnds);
39005 var simplifiedMultiLineString = new ol.geom.MultiLineString(null);
39006 simplifiedMultiLineString.setFlatCoordinates(
39007 ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEnds);
39008 return simplifiedMultiLineString;
39009};
39010
39011
39012/**
39013 * @inheritDoc
39014 * @api
39015 */
39016ol.geom.MultiLineString.prototype.getType = function() {
39017 return ol.geom.GeometryType.MULTI_LINE_STRING;
39018};
39019
39020
39021/**
39022 * @inheritDoc
39023 * @api
39024 */
39025ol.geom.MultiLineString.prototype.intersectsExtent = function(extent) {
39026 return ol.geom.flat.intersectsextent.lineStrings(
39027 this.flatCoordinates, 0, this.ends_, this.stride, extent);
39028};
39029
39030
39031/**
39032 * Set the coordinates of the multilinestring.
39033 * @param {Array.<Array.<ol.Coordinate>>} coordinates Coordinates.
39034 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
39035 * @override
39036 * @api
39037 */
39038ol.geom.MultiLineString.prototype.setCoordinates = function(coordinates, opt_layout) {
39039 if (!coordinates) {
39040 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.ends_);
39041 } else {
39042 this.setLayout(opt_layout, coordinates, 2);
39043 if (!this.flatCoordinates) {
39044 this.flatCoordinates = [];
39045 }
39046 var ends = ol.geom.flat.deflate.coordinatess(
39047 this.flatCoordinates, 0, coordinates, this.stride, this.ends_);
39048 this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
39049 this.changed();
39050 }
39051};
39052
39053
39054/**
39055 * @param {ol.geom.GeometryLayout} layout Layout.
39056 * @param {Array.<number>} flatCoordinates Flat coordinates.
39057 * @param {Array.<number>} ends Ends.
39058 */
39059ol.geom.MultiLineString.prototype.setFlatCoordinates = function(layout, flatCoordinates, ends) {
39060 this.setFlatCoordinatesInternal(layout, flatCoordinates);
39061 this.ends_ = ends;
39062 this.changed();
39063};
39064
39065
39066/**
39067 * @param {Array.<ol.geom.LineString>} lineStrings LineStrings.
39068 */
39069ol.geom.MultiLineString.prototype.setLineStrings = function(lineStrings) {
39070 var layout = this.getLayout();
39071 var flatCoordinates = [];
39072 var ends = [];
39073 var i, ii;
39074 for (i = 0, ii = lineStrings.length; i < ii; ++i) {
39075 var lineString = lineStrings[i];
39076 if (i === 0) {
39077 layout = lineString.getLayout();
39078 }
39079 ol.array.extend(flatCoordinates, lineString.getFlatCoordinates());
39080 ends.push(flatCoordinates.length);
39081 }
39082 this.setFlatCoordinates(layout, flatCoordinates, ends);
39083};
39084
39085goog.provide('ol.geom.MultiPoint');
39086
39087goog.require('ol');
39088goog.require('ol.array');
39089goog.require('ol.extent');
39090goog.require('ol.geom.GeometryLayout');
39091goog.require('ol.geom.GeometryType');
39092goog.require('ol.geom.Point');
39093goog.require('ol.geom.SimpleGeometry');
39094goog.require('ol.geom.flat.deflate');
39095goog.require('ol.geom.flat.inflate');
39096goog.require('ol.math');
39097
39098
39099/**
39100 * @classdesc
39101 * Multi-point geometry.
39102 *
39103 * @constructor
39104 * @extends {ol.geom.SimpleGeometry}
39105 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
39106 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
39107 * @api
39108 */
39109ol.geom.MultiPoint = function(coordinates, opt_layout) {
39110 ol.geom.SimpleGeometry.call(this);
39111 this.setCoordinates(coordinates, opt_layout);
39112};
39113ol.inherits(ol.geom.MultiPoint, ol.geom.SimpleGeometry);
39114
39115
39116/**
39117 * Append the passed point to this multipoint.
39118 * @param {ol.geom.Point} point Point.
39119 * @api
39120 */
39121ol.geom.MultiPoint.prototype.appendPoint = function(point) {
39122 if (!this.flatCoordinates) {
39123 this.flatCoordinates = point.getFlatCoordinates().slice();
39124 } else {
39125 ol.array.extend(this.flatCoordinates, point.getFlatCoordinates());
39126 }
39127 this.changed();
39128};
39129
39130
39131/**
39132 * Make a complete copy of the geometry.
39133 * @return {!ol.geom.MultiPoint} Clone.
39134 * @override
39135 * @api
39136 */
39137ol.geom.MultiPoint.prototype.clone = function() {
39138 var multiPoint = new ol.geom.MultiPoint(null);
39139 multiPoint.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
39140 return multiPoint;
39141};
39142
39143
39144/**
39145 * @inheritDoc
39146 */
39147ol.geom.MultiPoint.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
39148 if (minSquaredDistance <
39149 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
39150 return minSquaredDistance;
39151 }
39152 var flatCoordinates = this.flatCoordinates;
39153 var stride = this.stride;
39154 var i, ii, j;
39155 for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
39156 var squaredDistance = ol.math.squaredDistance(
39157 x, y, flatCoordinates[i], flatCoordinates[i + 1]);
39158 if (squaredDistance < minSquaredDistance) {
39159 minSquaredDistance = squaredDistance;
39160 for (j = 0; j < stride; ++j) {
39161 closestPoint[j] = flatCoordinates[i + j];
39162 }
39163 closestPoint.length = stride;
39164 }
39165 }
39166 return minSquaredDistance;
39167};
39168
39169
39170/**
39171 * Return the coordinates of the multipoint.
39172 * @return {Array.<ol.Coordinate>} Coordinates.
39173 * @override
39174 * @api
39175 */
39176ol.geom.MultiPoint.prototype.getCoordinates = function() {
39177 return ol.geom.flat.inflate.coordinates(
39178 this.flatCoordinates, 0, this.flatCoordinates.length, this.stride);
39179};
39180
39181
39182/**
39183 * Return the point at the specified index.
39184 * @param {number} index Index.
39185 * @return {ol.geom.Point} Point.
39186 * @api
39187 */
39188ol.geom.MultiPoint.prototype.getPoint = function(index) {
39189 var n = !this.flatCoordinates ?
39190 0 : this.flatCoordinates.length / this.stride;
39191 if (index < 0 || n <= index) {
39192 return null;
39193 }
39194 var point = new ol.geom.Point(null);
39195 point.setFlatCoordinates(this.layout, this.flatCoordinates.slice(
39196 index * this.stride, (index + 1) * this.stride));
39197 return point;
39198};
39199
39200
39201/**
39202 * Return the points of this multipoint.
39203 * @return {Array.<ol.geom.Point>} Points.
39204 * @api
39205 */
39206ol.geom.MultiPoint.prototype.getPoints = function() {
39207 var flatCoordinates = this.flatCoordinates;
39208 var layout = this.layout;
39209 var stride = this.stride;
39210 /** @type {Array.<ol.geom.Point>} */
39211 var points = [];
39212 var i, ii;
39213 for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
39214 var point = new ol.geom.Point(null);
39215 point.setFlatCoordinates(layout, flatCoordinates.slice(i, i + stride));
39216 points.push(point);
39217 }
39218 return points;
39219};
39220
39221
39222/**
39223 * @inheritDoc
39224 * @api
39225 */
39226ol.geom.MultiPoint.prototype.getType = function() {
39227 return ol.geom.GeometryType.MULTI_POINT;
39228};
39229
39230
39231/**
39232 * @inheritDoc
39233 * @api
39234 */
39235ol.geom.MultiPoint.prototype.intersectsExtent = function(extent) {
39236 var flatCoordinates = this.flatCoordinates;
39237 var stride = this.stride;
39238 var i, ii, x, y;
39239 for (i = 0, ii = flatCoordinates.length; i < ii; i += stride) {
39240 x = flatCoordinates[i];
39241 y = flatCoordinates[i + 1];
39242 if (ol.extent.containsXY(extent, x, y)) {
39243 return true;
39244 }
39245 }
39246 return false;
39247};
39248
39249
39250/**
39251 * Set the coordinates of the multipoint.
39252 * @param {Array.<ol.Coordinate>} coordinates Coordinates.
39253 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
39254 * @override
39255 * @api
39256 */
39257ol.geom.MultiPoint.prototype.setCoordinates = function(coordinates, opt_layout) {
39258 if (!coordinates) {
39259 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
39260 } else {
39261 this.setLayout(opt_layout, coordinates, 1);
39262 if (!this.flatCoordinates) {
39263 this.flatCoordinates = [];
39264 }
39265 this.flatCoordinates.length = ol.geom.flat.deflate.coordinates(
39266 this.flatCoordinates, 0, coordinates, this.stride);
39267 this.changed();
39268 }
39269};
39270
39271
39272/**
39273 * @param {ol.geom.GeometryLayout} layout Layout.
39274 * @param {Array.<number>} flatCoordinates Flat coordinates.
39275 */
39276ol.geom.MultiPoint.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
39277 this.setFlatCoordinatesInternal(layout, flatCoordinates);
39278 this.changed();
39279};
39280
39281goog.provide('ol.geom.flat.center');
39282
39283goog.require('ol.extent');
39284
39285
39286/**
39287 * @param {Array.<number>} flatCoordinates Flat coordinates.
39288 * @param {number} offset Offset.
39289 * @param {Array.<Array.<number>>} endss Endss.
39290 * @param {number} stride Stride.
39291 * @return {Array.<number>} Flat centers.
39292 */
39293ol.geom.flat.center.linearRingss = function(flatCoordinates, offset, endss, stride) {
39294 var flatCenters = [];
39295 var i, ii;
39296 var extent = ol.extent.createEmpty();
39297 for (i = 0, ii = endss.length; i < ii; ++i) {
39298 var ends = endss[i];
39299 extent = ol.extent.createOrUpdateFromFlatCoordinates(
39300 flatCoordinates, offset, ends[0], stride);
39301 flatCenters.push((extent[0] + extent[2]) / 2, (extent[1] + extent[3]) / 2);
39302 offset = ends[ends.length - 1];
39303 }
39304 return flatCenters;
39305};
39306
39307goog.provide('ol.geom.MultiPolygon');
39308
39309goog.require('ol');
39310goog.require('ol.array');
39311goog.require('ol.extent');
39312goog.require('ol.geom.GeometryLayout');
39313goog.require('ol.geom.GeometryType');
39314goog.require('ol.geom.MultiPoint');
39315goog.require('ol.geom.Polygon');
39316goog.require('ol.geom.SimpleGeometry');
39317goog.require('ol.geom.flat.area');
39318goog.require('ol.geom.flat.center');
39319goog.require('ol.geom.flat.closest');
39320goog.require('ol.geom.flat.contains');
39321goog.require('ol.geom.flat.deflate');
39322goog.require('ol.geom.flat.inflate');
39323goog.require('ol.geom.flat.interiorpoint');
39324goog.require('ol.geom.flat.intersectsextent');
39325goog.require('ol.geom.flat.orient');
39326goog.require('ol.geom.flat.simplify');
39327
39328
39329/**
39330 * @classdesc
39331 * Multi-polygon geometry.
39332 *
39333 * @constructor
39334 * @extends {ol.geom.SimpleGeometry}
39335 * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
39336 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
39337 * @api
39338 */
39339ol.geom.MultiPolygon = function(coordinates, opt_layout) {
39340
39341 ol.geom.SimpleGeometry.call(this);
39342
39343 /**
39344 * @type {Array.<Array.<number>>}
39345 * @private
39346 */
39347 this.endss_ = [];
39348
39349 /**
39350 * @private
39351 * @type {number}
39352 */
39353 this.flatInteriorPointsRevision_ = -1;
39354
39355 /**
39356 * @private
39357 * @type {Array.<number>}
39358 */
39359 this.flatInteriorPoints_ = null;
39360
39361 /**
39362 * @private
39363 * @type {number}
39364 */
39365 this.maxDelta_ = -1;
39366
39367 /**
39368 * @private
39369 * @type {number}
39370 */
39371 this.maxDeltaRevision_ = -1;
39372
39373 /**
39374 * @private
39375 * @type {number}
39376 */
39377 this.orientedRevision_ = -1;
39378
39379 /**
39380 * @private
39381 * @type {Array.<number>}
39382 */
39383 this.orientedFlatCoordinates_ = null;
39384
39385 this.setCoordinates(coordinates, opt_layout);
39386
39387};
39388ol.inherits(ol.geom.MultiPolygon, ol.geom.SimpleGeometry);
39389
39390
39391/**
39392 * Append the passed polygon to this multipolygon.
39393 * @param {ol.geom.Polygon} polygon Polygon.
39394 * @api
39395 */
39396ol.geom.MultiPolygon.prototype.appendPolygon = function(polygon) {
39397 /** @type {Array.<number>} */
39398 var ends;
39399 if (!this.flatCoordinates) {
39400 this.flatCoordinates = polygon.getFlatCoordinates().slice();
39401 ends = polygon.getEnds().slice();
39402 this.endss_.push();
39403 } else {
39404 var offset = this.flatCoordinates.length;
39405 ol.array.extend(this.flatCoordinates, polygon.getFlatCoordinates());
39406 ends = polygon.getEnds().slice();
39407 var i, ii;
39408 for (i = 0, ii = ends.length; i < ii; ++i) {
39409 ends[i] += offset;
39410 }
39411 }
39412 this.endss_.push(ends);
39413 this.changed();
39414};
39415
39416
39417/**
39418 * Make a complete copy of the geometry.
39419 * @return {!ol.geom.MultiPolygon} Clone.
39420 * @override
39421 * @api
39422 */
39423ol.geom.MultiPolygon.prototype.clone = function() {
39424 var multiPolygon = new ol.geom.MultiPolygon(null);
39425
39426 var len = this.endss_.length;
39427 var newEndss = new Array(len);
39428 for (var i = 0; i < len; ++i) {
39429 newEndss[i] = this.endss_[i].slice();
39430 }
39431
39432 multiPolygon.setFlatCoordinates(
39433 this.layout, this.flatCoordinates.slice(), newEndss);
39434 return multiPolygon;
39435};
39436
39437
39438/**
39439 * @inheritDoc
39440 */
39441ol.geom.MultiPolygon.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
39442 if (minSquaredDistance <
39443 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
39444 return minSquaredDistance;
39445 }
39446 if (this.maxDeltaRevision_ != this.getRevision()) {
39447 this.maxDelta_ = Math.sqrt(ol.geom.flat.closest.getssMaxSquaredDelta(
39448 this.flatCoordinates, 0, this.endss_, this.stride, 0));
39449 this.maxDeltaRevision_ = this.getRevision();
39450 }
39451 return ol.geom.flat.closest.getssClosestPoint(
39452 this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
39453 this.maxDelta_, true, x, y, closestPoint, minSquaredDistance);
39454};
39455
39456
39457/**
39458 * @inheritDoc
39459 */
39460ol.geom.MultiPolygon.prototype.containsXY = function(x, y) {
39461 return ol.geom.flat.contains.linearRingssContainsXY(
39462 this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, x, y);
39463};
39464
39465
39466/**
39467 * Return the area of the multipolygon on projected plane.
39468 * @return {number} Area (on projected plane).
39469 * @api
39470 */
39471ol.geom.MultiPolygon.prototype.getArea = function() {
39472 return ol.geom.flat.area.linearRingss(
39473 this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride);
39474};
39475
39476
39477/**
39478 * Get the coordinate array for this geometry. This array has the structure
39479 * of a GeoJSON coordinate array for multi-polygons.
39480 *
39481 * @param {boolean=} opt_right Orient coordinates according to the right-hand
39482 * rule (counter-clockwise for exterior and clockwise for interior rings).
39483 * If `false`, coordinates will be oriented according to the left-hand rule
39484 * (clockwise for exterior and counter-clockwise for interior rings).
39485 * By default, coordinate orientation will depend on how the geometry was
39486 * constructed.
39487 * @return {Array.<Array.<Array.<ol.Coordinate>>>} Coordinates.
39488 * @override
39489 * @api
39490 */
39491ol.geom.MultiPolygon.prototype.getCoordinates = function(opt_right) {
39492 var flatCoordinates;
39493 if (opt_right !== undefined) {
39494 flatCoordinates = this.getOrientedFlatCoordinates().slice();
39495 ol.geom.flat.orient.orientLinearRingss(
39496 flatCoordinates, 0, this.endss_, this.stride, opt_right);
39497 } else {
39498 flatCoordinates = this.flatCoordinates;
39499 }
39500
39501 return ol.geom.flat.inflate.coordinatesss(
39502 flatCoordinates, 0, this.endss_, this.stride);
39503};
39504
39505
39506/**
39507 * @return {Array.<Array.<number>>} Endss.
39508 */
39509ol.geom.MultiPolygon.prototype.getEndss = function() {
39510 return this.endss_;
39511};
39512
39513
39514/**
39515 * @return {Array.<number>} Flat interior points.
39516 */
39517ol.geom.MultiPolygon.prototype.getFlatInteriorPoints = function() {
39518 if (this.flatInteriorPointsRevision_ != this.getRevision()) {
39519 var flatCenters = ol.geom.flat.center.linearRingss(
39520 this.flatCoordinates, 0, this.endss_, this.stride);
39521 this.flatInteriorPoints_ = ol.geom.flat.interiorpoint.linearRingss(
39522 this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride,
39523 flatCenters);
39524 this.flatInteriorPointsRevision_ = this.getRevision();
39525 }
39526 return this.flatInteriorPoints_;
39527};
39528
39529
39530/**
39531 * Return the interior points as {@link ol.geom.MultiPoint multipoint}.
39532 * @return {ol.geom.MultiPoint} Interior points.
39533 * @api
39534 */
39535ol.geom.MultiPolygon.prototype.getInteriorPoints = function() {
39536 var interiorPoints = new ol.geom.MultiPoint(null);
39537 interiorPoints.setFlatCoordinates(ol.geom.GeometryLayout.XY,
39538 this.getFlatInteriorPoints().slice());
39539 return interiorPoints;
39540};
39541
39542
39543/**
39544 * @return {Array.<number>} Oriented flat coordinates.
39545 */
39546ol.geom.MultiPolygon.prototype.getOrientedFlatCoordinates = function() {
39547 if (this.orientedRevision_ != this.getRevision()) {
39548 var flatCoordinates = this.flatCoordinates;
39549 if (ol.geom.flat.orient.linearRingssAreOriented(
39550 flatCoordinates, 0, this.endss_, this.stride)) {
39551 this.orientedFlatCoordinates_ = flatCoordinates;
39552 } else {
39553 this.orientedFlatCoordinates_ = flatCoordinates.slice();
39554 this.orientedFlatCoordinates_.length =
39555 ol.geom.flat.orient.orientLinearRingss(
39556 this.orientedFlatCoordinates_, 0, this.endss_, this.stride);
39557 }
39558 this.orientedRevision_ = this.getRevision();
39559 }
39560 return this.orientedFlatCoordinates_;
39561};
39562
39563
39564/**
39565 * @inheritDoc
39566 */
39567ol.geom.MultiPolygon.prototype.getSimplifiedGeometryInternal = function(squaredTolerance) {
39568 var simplifiedFlatCoordinates = [];
39569 var simplifiedEndss = [];
39570 simplifiedFlatCoordinates.length = ol.geom.flat.simplify.quantizess(
39571 this.flatCoordinates, 0, this.endss_, this.stride,
39572 Math.sqrt(squaredTolerance),
39573 simplifiedFlatCoordinates, 0, simplifiedEndss);
39574 var simplifiedMultiPolygon = new ol.geom.MultiPolygon(null);
39575 simplifiedMultiPolygon.setFlatCoordinates(
39576 ol.geom.GeometryLayout.XY, simplifiedFlatCoordinates, simplifiedEndss);
39577 return simplifiedMultiPolygon;
39578};
39579
39580
39581/**
39582 * Return the polygon at the specified index.
39583 * @param {number} index Index.
39584 * @return {ol.geom.Polygon} Polygon.
39585 * @api
39586 */
39587ol.geom.MultiPolygon.prototype.getPolygon = function(index) {
39588 if (index < 0 || this.endss_.length <= index) {
39589 return null;
39590 }
39591 var offset;
39592 if (index === 0) {
39593 offset = 0;
39594 } else {
39595 var prevEnds = this.endss_[index - 1];
39596 offset = prevEnds[prevEnds.length - 1];
39597 }
39598 var ends = this.endss_[index].slice();
39599 var end = ends[ends.length - 1];
39600 if (offset !== 0) {
39601 var i, ii;
39602 for (i = 0, ii = ends.length; i < ii; ++i) {
39603 ends[i] -= offset;
39604 }
39605 }
39606 var polygon = new ol.geom.Polygon(null);
39607 polygon.setFlatCoordinates(
39608 this.layout, this.flatCoordinates.slice(offset, end), ends);
39609 return polygon;
39610};
39611
39612
39613/**
39614 * Return the polygons of this multipolygon.
39615 * @return {Array.<ol.geom.Polygon>} Polygons.
39616 * @api
39617 */
39618ol.geom.MultiPolygon.prototype.getPolygons = function() {
39619 var layout = this.layout;
39620 var flatCoordinates = this.flatCoordinates;
39621 var endss = this.endss_;
39622 var polygons = [];
39623 var offset = 0;
39624 var i, ii, j, jj;
39625 for (i = 0, ii = endss.length; i < ii; ++i) {
39626 var ends = endss[i].slice();
39627 var end = ends[ends.length - 1];
39628 if (offset !== 0) {
39629 for (j = 0, jj = ends.length; j < jj; ++j) {
39630 ends[j] -= offset;
39631 }
39632 }
39633 var polygon = new ol.geom.Polygon(null);
39634 polygon.setFlatCoordinates(
39635 layout, flatCoordinates.slice(offset, end), ends);
39636 polygons.push(polygon);
39637 offset = end;
39638 }
39639 return polygons;
39640};
39641
39642
39643/**
39644 * @inheritDoc
39645 * @api
39646 */
39647ol.geom.MultiPolygon.prototype.getType = function() {
39648 return ol.geom.GeometryType.MULTI_POLYGON;
39649};
39650
39651
39652/**
39653 * @inheritDoc
39654 * @api
39655 */
39656ol.geom.MultiPolygon.prototype.intersectsExtent = function(extent) {
39657 return ol.geom.flat.intersectsextent.linearRingss(
39658 this.getOrientedFlatCoordinates(), 0, this.endss_, this.stride, extent);
39659};
39660
39661
39662/**
39663 * Set the coordinates of the multipolygon.
39664 * @param {Array.<Array.<Array.<ol.Coordinate>>>} coordinates Coordinates.
39665 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
39666 * @override
39667 * @api
39668 */
39669ol.geom.MultiPolygon.prototype.setCoordinates = function(coordinates, opt_layout) {
39670 if (!coordinates) {
39671 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null, this.endss_);
39672 } else {
39673 this.setLayout(opt_layout, coordinates, 3);
39674 if (!this.flatCoordinates) {
39675 this.flatCoordinates = [];
39676 }
39677 var endss = ol.geom.flat.deflate.coordinatesss(
39678 this.flatCoordinates, 0, coordinates, this.stride, this.endss_);
39679 if (endss.length === 0) {
39680 this.flatCoordinates.length = 0;
39681 } else {
39682 var lastEnds = endss[endss.length - 1];
39683 this.flatCoordinates.length = lastEnds.length === 0 ?
39684 0 : lastEnds[lastEnds.length - 1];
39685 }
39686 this.changed();
39687 }
39688};
39689
39690
39691/**
39692 * @param {ol.geom.GeometryLayout} layout Layout.
39693 * @param {Array.<number>} flatCoordinates Flat coordinates.
39694 * @param {Array.<Array.<number>>} endss Endss.
39695 */
39696ol.geom.MultiPolygon.prototype.setFlatCoordinates = function(layout, flatCoordinates, endss) {
39697 this.setFlatCoordinatesInternal(layout, flatCoordinates);
39698 this.endss_ = endss;
39699 this.changed();
39700};
39701
39702
39703/**
39704 * @param {Array.<ol.geom.Polygon>} polygons Polygons.
39705 */
39706ol.geom.MultiPolygon.prototype.setPolygons = function(polygons) {
39707 var layout = this.getLayout();
39708 var flatCoordinates = [];
39709 var endss = [];
39710 var i, ii, ends;
39711 for (i = 0, ii = polygons.length; i < ii; ++i) {
39712 var polygon = polygons[i];
39713 if (i === 0) {
39714 layout = polygon.getLayout();
39715 }
39716 var offset = flatCoordinates.length;
39717 ends = polygon.getEnds();
39718 var j, jj;
39719 for (j = 0, jj = ends.length; j < jj; ++j) {
39720 ends[j] += offset;
39721 }
39722 ol.array.extend(flatCoordinates, polygon.getFlatCoordinates());
39723 endss.push(ends);
39724 }
39725 this.setFlatCoordinates(layout, flatCoordinates, endss);
39726};
39727
39728goog.provide('ol.format.EsriJSON');
39729
39730goog.require('ol');
39731goog.require('ol.Feature');
39732goog.require('ol.asserts');
39733goog.require('ol.extent');
39734goog.require('ol.format.Feature');
39735goog.require('ol.format.JSONFeature');
39736goog.require('ol.geom.GeometryLayout');
39737goog.require('ol.geom.GeometryType');
39738goog.require('ol.geom.LineString');
39739goog.require('ol.geom.LinearRing');
39740goog.require('ol.geom.MultiLineString');
39741goog.require('ol.geom.MultiPoint');
39742goog.require('ol.geom.MultiPolygon');
39743goog.require('ol.geom.Point');
39744goog.require('ol.geom.Polygon');
39745goog.require('ol.geom.flat.deflate');
39746goog.require('ol.geom.flat.orient');
39747goog.require('ol.obj');
39748goog.require('ol.proj');
39749
39750
39751/**
39752 * @classdesc
39753 * Feature format for reading and writing data in the EsriJSON format.
39754 *
39755 * @constructor
39756 * @extends {ol.format.JSONFeature}
39757 * @param {olx.format.EsriJSONOptions=} opt_options Options.
39758 * @api
39759 */
39760ol.format.EsriJSON = function(opt_options) {
39761
39762 var options = opt_options ? opt_options : {};
39763
39764 ol.format.JSONFeature.call(this);
39765
39766 /**
39767 * Name of the geometry attribute for features.
39768 * @type {string|undefined}
39769 * @private
39770 */
39771 this.geometryName_ = options.geometryName;
39772
39773};
39774ol.inherits(ol.format.EsriJSON, ol.format.JSONFeature);
39775
39776
39777/**
39778 * @param {EsriJSONGeometry} object Object.
39779 * @param {olx.format.ReadOptions=} opt_options Read options.
39780 * @private
39781 * @return {ol.geom.Geometry} Geometry.
39782 */
39783ol.format.EsriJSON.readGeometry_ = function(object, opt_options) {
39784 if (!object) {
39785 return null;
39786 }
39787 /** @type {ol.geom.GeometryType} */
39788 var type;
39789 if (typeof object.x === 'number' && typeof object.y === 'number') {
39790 type = ol.geom.GeometryType.POINT;
39791 } else if (object.points) {
39792 type = ol.geom.GeometryType.MULTI_POINT;
39793 } else if (object.paths) {
39794 if (object.paths.length === 1) {
39795 type = ol.geom.GeometryType.LINE_STRING;
39796 } else {
39797 type = ol.geom.GeometryType.MULTI_LINE_STRING;
39798 }
39799 } else if (object.rings) {
39800 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39801 var rings = ol.format.EsriJSON.convertRings_(object.rings, layout);
39802 object = /** @type {EsriJSONGeometry} */(ol.obj.assign({}, object));
39803 if (rings.length === 1) {
39804 type = ol.geom.GeometryType.POLYGON;
39805 object.rings = rings[0];
39806 } else {
39807 type = ol.geom.GeometryType.MULTI_POLYGON;
39808 object.rings = rings;
39809 }
39810 }
39811 var geometryReader = ol.format.EsriJSON.GEOMETRY_READERS_[type];
39812 return /** @type {ol.geom.Geometry} */ (
39813 ol.format.Feature.transformWithOptions(
39814 geometryReader(object), false, opt_options));
39815};
39816
39817
39818/**
39819 * Determines inner and outer rings.
39820 * Checks if any polygons in this array contain any other polygons in this
39821 * array. It is used for checking for holes.
39822 * Logic inspired by: https://github.com/Esri/terraformer-arcgis-parser
39823 * @param {Array.<!Array.<!Array.<number>>>} rings Rings.
39824 * @param {ol.geom.GeometryLayout} layout Geometry layout.
39825 * @private
39826 * @return {Array.<!Array.<!Array.<number>>>} Transformed rings.
39827 */
39828ol.format.EsriJSON.convertRings_ = function(rings, layout) {
39829 var flatRing = [];
39830 var outerRings = [];
39831 var holes = [];
39832 var i, ii;
39833 for (i = 0, ii = rings.length; i < ii; ++i) {
39834 flatRing.length = 0;
39835 ol.geom.flat.deflate.coordinates(flatRing, 0, rings[i], layout.length);
39836 // is this ring an outer ring? is it clockwise?
39837 var clockwise = ol.geom.flat.orient.linearRingIsClockwise(flatRing, 0,
39838 flatRing.length, layout.length);
39839 if (clockwise) {
39840 outerRings.push([rings[i]]);
39841 } else {
39842 holes.push(rings[i]);
39843 }
39844 }
39845 while (holes.length) {
39846 var hole = holes.shift();
39847 var matched = false;
39848 // loop over all outer rings and see if they contain our hole.
39849 for (i = outerRings.length - 1; i >= 0; i--) {
39850 var outerRing = outerRings[i][0];
39851 var containsHole = ol.extent.containsExtent(
39852 new ol.geom.LinearRing(outerRing).getExtent(),
39853 new ol.geom.LinearRing(hole).getExtent()
39854 );
39855 if (containsHole) {
39856 // the hole is contained push it into our polygon
39857 outerRings[i].push(hole);
39858 matched = true;
39859 break;
39860 }
39861 }
39862 if (!matched) {
39863 // no outer rings contain this hole turn it into and outer
39864 // ring (reverse it)
39865 outerRings.push([hole.reverse()]);
39866 }
39867 }
39868 return outerRings;
39869};
39870
39871
39872/**
39873 * @param {EsriJSONGeometry} object Object.
39874 * @private
39875 * @return {ol.geom.Geometry} Point.
39876 */
39877ol.format.EsriJSON.readPointGeometry_ = function(object) {
39878 var point;
39879 if (object.m !== undefined && object.z !== undefined) {
39880 point = new ol.geom.Point([object.x, object.y, object.z, object.m],
39881 ol.geom.GeometryLayout.XYZM);
39882 } else if (object.z !== undefined) {
39883 point = new ol.geom.Point([object.x, object.y, object.z],
39884 ol.geom.GeometryLayout.XYZ);
39885 } else if (object.m !== undefined) {
39886 point = new ol.geom.Point([object.x, object.y, object.m],
39887 ol.geom.GeometryLayout.XYM);
39888 } else {
39889 point = new ol.geom.Point([object.x, object.y]);
39890 }
39891 return point;
39892};
39893
39894
39895/**
39896 * @param {EsriJSONGeometry} object Object.
39897 * @private
39898 * @return {ol.geom.Geometry} LineString.
39899 */
39900ol.format.EsriJSON.readLineStringGeometry_ = function(object) {
39901 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39902 return new ol.geom.LineString(object.paths[0], layout);
39903};
39904
39905
39906/**
39907 * @param {EsriJSONGeometry} object Object.
39908 * @private
39909 * @return {ol.geom.Geometry} MultiLineString.
39910 */
39911ol.format.EsriJSON.readMultiLineStringGeometry_ = function(object) {
39912 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39913 return new ol.geom.MultiLineString(object.paths, layout);
39914};
39915
39916
39917/**
39918 * @param {EsriJSONGeometry} object Object.
39919 * @private
39920 * @return {ol.geom.GeometryLayout} The geometry layout to use.
39921 */
39922ol.format.EsriJSON.getGeometryLayout_ = function(object) {
39923 var layout = ol.geom.GeometryLayout.XY;
39924 if (object.hasZ === true && object.hasM === true) {
39925 layout = ol.geom.GeometryLayout.XYZM;
39926 } else if (object.hasZ === true) {
39927 layout = ol.geom.GeometryLayout.XYZ;
39928 } else if (object.hasM === true) {
39929 layout = ol.geom.GeometryLayout.XYM;
39930 }
39931 return layout;
39932};
39933
39934
39935/**
39936 * @param {EsriJSONGeometry} object Object.
39937 * @private
39938 * @return {ol.geom.Geometry} MultiPoint.
39939 */
39940ol.format.EsriJSON.readMultiPointGeometry_ = function(object) {
39941 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39942 return new ol.geom.MultiPoint(object.points, layout);
39943};
39944
39945
39946/**
39947 * @param {EsriJSONGeometry} object Object.
39948 * @private
39949 * @return {ol.geom.Geometry} MultiPolygon.
39950 */
39951ol.format.EsriJSON.readMultiPolygonGeometry_ = function(object) {
39952 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39953 return new ol.geom.MultiPolygon(
39954 /** @type {Array.<Array.<Array.<Array.<number>>>>} */(object.rings),
39955 layout);
39956};
39957
39958
39959/**
39960 * @param {EsriJSONGeometry} object Object.
39961 * @private
39962 * @return {ol.geom.Geometry} Polygon.
39963 */
39964ol.format.EsriJSON.readPolygonGeometry_ = function(object) {
39965 var layout = ol.format.EsriJSON.getGeometryLayout_(object);
39966 return new ol.geom.Polygon(object.rings, layout);
39967};
39968
39969
39970/**
39971 * @param {ol.geom.Geometry} geometry Geometry.
39972 * @param {olx.format.WriteOptions=} opt_options Write options.
39973 * @private
39974 * @return {EsriJSONGeometry} EsriJSON geometry.
39975 */
39976ol.format.EsriJSON.writePointGeometry_ = function(geometry, opt_options) {
39977 var coordinates = /** @type {ol.geom.Point} */ (geometry).getCoordinates();
39978 var esriJSON;
39979 var layout = /** @type {ol.geom.Point} */ (geometry).getLayout();
39980 if (layout === ol.geom.GeometryLayout.XYZ) {
39981 esriJSON = /** @type {EsriJSONPoint} */ ({
39982 x: coordinates[0],
39983 y: coordinates[1],
39984 z: coordinates[2]
39985 });
39986 } else if (layout === ol.geom.GeometryLayout.XYM) {
39987 esriJSON = /** @type {EsriJSONPoint} */ ({
39988 x: coordinates[0],
39989 y: coordinates[1],
39990 m: coordinates[2]
39991 });
39992 } else if (layout === ol.geom.GeometryLayout.XYZM) {
39993 esriJSON = /** @type {EsriJSONPoint} */ ({
39994 x: coordinates[0],
39995 y: coordinates[1],
39996 z: coordinates[2],
39997 m: coordinates[3]
39998 });
39999 } else if (layout === ol.geom.GeometryLayout.XY) {
40000 esriJSON = /** @type {EsriJSONPoint} */ ({
40001 x: coordinates[0],
40002 y: coordinates[1]
40003 });
40004 } else {
40005 ol.asserts.assert(false, 34); // Invalid geometry layout
40006 }
40007 return /** @type {EsriJSONGeometry} */ (esriJSON);
40008};
40009
40010
40011/**
40012 * @param {ol.geom.SimpleGeometry} geometry Geometry.
40013 * @private
40014 * @return {Object} Object with boolean hasZ and hasM keys.
40015 */
40016ol.format.EsriJSON.getHasZM_ = function(geometry) {
40017 var layout = geometry.getLayout();
40018 return {
40019 hasZ: (layout === ol.geom.GeometryLayout.XYZ ||
40020 layout === ol.geom.GeometryLayout.XYZM),
40021 hasM: (layout === ol.geom.GeometryLayout.XYM ||
40022 layout === ol.geom.GeometryLayout.XYZM)
40023 };
40024};
40025
40026
40027/**
40028 * @param {ol.geom.Geometry} geometry Geometry.
40029 * @param {olx.format.WriteOptions=} opt_options Write options.
40030 * @private
40031 * @return {EsriJSONPolyline} EsriJSON geometry.
40032 */
40033ol.format.EsriJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
40034 var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.LineString} */(geometry));
40035 return /** @type {EsriJSONPolyline} */ ({
40036 hasZ: hasZM.hasZ,
40037 hasM: hasZM.hasM,
40038 paths: [
40039 /** @type {ol.geom.LineString} */ (geometry).getCoordinates()
40040 ]
40041 });
40042};
40043
40044
40045/**
40046 * @param {ol.geom.Geometry} geometry Geometry.
40047 * @param {olx.format.WriteOptions=} opt_options Write options.
40048 * @private
40049 * @return {EsriJSONPolygon} EsriJSON geometry.
40050 */
40051ol.format.EsriJSON.writePolygonGeometry_ = function(geometry, opt_options) {
40052 // Esri geometries use the left-hand rule
40053 var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.Polygon} */(geometry));
40054 return /** @type {EsriJSONPolygon} */ ({
40055 hasZ: hasZM.hasZ,
40056 hasM: hasZM.hasM,
40057 rings: /** @type {ol.geom.Polygon} */ (geometry).getCoordinates(false)
40058 });
40059};
40060
40061
40062/**
40063 * @param {ol.geom.Geometry} geometry Geometry.
40064 * @param {olx.format.WriteOptions=} opt_options Write options.
40065 * @private
40066 * @return {EsriJSONPolyline} EsriJSON geometry.
40067 */
40068ol.format.EsriJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {
40069 var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiLineString} */(geometry));
40070 return /** @type {EsriJSONPolyline} */ ({
40071 hasZ: hasZM.hasZ,
40072 hasM: hasZM.hasM,
40073 paths: /** @type {ol.geom.MultiLineString} */ (geometry).getCoordinates()
40074 });
40075};
40076
40077
40078/**
40079 * @param {ol.geom.Geometry} geometry Geometry.
40080 * @param {olx.format.WriteOptions=} opt_options Write options.
40081 * @private
40082 * @return {EsriJSONMultipoint} EsriJSON geometry.
40083 */
40084ol.format.EsriJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
40085 var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiPoint} */(geometry));
40086 return /** @type {EsriJSONMultipoint} */ ({
40087 hasZ: hasZM.hasZ,
40088 hasM: hasZM.hasM,
40089 points: /** @type {ol.geom.MultiPoint} */ (geometry).getCoordinates()
40090 });
40091};
40092
40093
40094/**
40095 * @param {ol.geom.Geometry} geometry Geometry.
40096 * @param {olx.format.WriteOptions=} opt_options Write options.
40097 * @private
40098 * @return {EsriJSONPolygon} EsriJSON geometry.
40099 */
40100ol.format.EsriJSON.writeMultiPolygonGeometry_ = function(geometry,
40101 opt_options) {
40102 var hasZM = ol.format.EsriJSON.getHasZM_(/** @type {ol.geom.MultiPolygon} */(geometry));
40103 var coordinates = /** @type {ol.geom.MultiPolygon} */ (geometry).getCoordinates(false);
40104 var output = [];
40105 for (var i = 0; i < coordinates.length; i++) {
40106 for (var x = coordinates[i].length - 1; x >= 0; x--) {
40107 output.push(coordinates[i][x]);
40108 }
40109 }
40110 return /** @type {EsriJSONPolygon} */ ({
40111 hasZ: hasZM.hasZ,
40112 hasM: hasZM.hasM,
40113 rings: output
40114 });
40115};
40116
40117
40118/**
40119 * @const
40120 * @private
40121 * @type {Object.<ol.geom.GeometryType, function(EsriJSONGeometry): ol.geom.Geometry>}
40122 */
40123ol.format.EsriJSON.GEOMETRY_READERS_ = {};
40124ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POINT] =
40125 ol.format.EsriJSON.readPointGeometry_;
40126ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.LINE_STRING] =
40127 ol.format.EsriJSON.readLineStringGeometry_;
40128ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.POLYGON] =
40129 ol.format.EsriJSON.readPolygonGeometry_;
40130ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POINT] =
40131 ol.format.EsriJSON.readMultiPointGeometry_;
40132ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =
40133 ol.format.EsriJSON.readMultiLineStringGeometry_;
40134ol.format.EsriJSON.GEOMETRY_READERS_[ol.geom.GeometryType.MULTI_POLYGON] =
40135 ol.format.EsriJSON.readMultiPolygonGeometry_;
40136
40137
40138/**
40139 * @const
40140 * @private
40141 * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (EsriJSONGeometry)>}
40142 */
40143ol.format.EsriJSON.GEOMETRY_WRITERS_ = {};
40144ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POINT] =
40145 ol.format.EsriJSON.writePointGeometry_;
40146ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.LINE_STRING] =
40147 ol.format.EsriJSON.writeLineStringGeometry_;
40148ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.POLYGON] =
40149 ol.format.EsriJSON.writePolygonGeometry_;
40150ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POINT] =
40151 ol.format.EsriJSON.writeMultiPointGeometry_;
40152ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_LINE_STRING] =
40153 ol.format.EsriJSON.writeMultiLineStringGeometry_;
40154ol.format.EsriJSON.GEOMETRY_WRITERS_[ol.geom.GeometryType.MULTI_POLYGON] =
40155 ol.format.EsriJSON.writeMultiPolygonGeometry_;
40156
40157
40158/**
40159 * Read a feature from a EsriJSON Feature source. Only works for Feature,
40160 * use `readFeatures` to read FeatureCollection source.
40161 *
40162 * @function
40163 * @param {ArrayBuffer|Document|Node|Object|string} source Source.
40164 * @param {olx.format.ReadOptions=} opt_options Read options.
40165 * @return {ol.Feature} Feature.
40166 * @api
40167 */
40168ol.format.EsriJSON.prototype.readFeature;
40169
40170
40171/**
40172 * Read all features from a EsriJSON source. Works with both Feature and
40173 * FeatureCollection sources.
40174 *
40175 * @function
40176 * @param {ArrayBuffer|Document|Node|Object|string} source Source.
40177 * @param {olx.format.ReadOptions=} opt_options Read options.
40178 * @return {Array.<ol.Feature>} Features.
40179 * @api
40180 */
40181ol.format.EsriJSON.prototype.readFeatures;
40182
40183
40184/**
40185 * @inheritDoc
40186 */
40187ol.format.EsriJSON.prototype.readFeatureFromObject = function(
40188 object, opt_options) {
40189 var esriJSONFeature = /** @type {EsriJSONFeature} */ (object);
40190 var geometry = ol.format.EsriJSON.readGeometry_(esriJSONFeature.geometry,
40191 opt_options);
40192 var feature = new ol.Feature();
40193 if (this.geometryName_) {
40194 feature.setGeometryName(this.geometryName_);
40195 }
40196 feature.setGeometry(geometry);
40197 if (opt_options && opt_options.idField &&
40198 esriJSONFeature.attributes[opt_options.idField]) {
40199 feature.setId(/** @type {number} */(
40200 esriJSONFeature.attributes[opt_options.idField]));
40201 }
40202 if (esriJSONFeature.attributes) {
40203 feature.setProperties(esriJSONFeature.attributes);
40204 }
40205 return feature;
40206};
40207
40208
40209/**
40210 * @inheritDoc
40211 */
40212ol.format.EsriJSON.prototype.readFeaturesFromObject = function(
40213 object, opt_options) {
40214 var esriJSONObject = /** @type {EsriJSONObject} */ (object);
40215 var options = opt_options ? opt_options : {};
40216 if (esriJSONObject.features) {
40217 var esriJSONFeatureCollection = /** @type {EsriJSONFeatureCollection} */
40218 (object);
40219 /** @type {Array.<ol.Feature>} */
40220 var features = [];
40221 var esriJSONFeatures = esriJSONFeatureCollection.features;
40222 var i, ii;
40223 options.idField = object.objectIdFieldName;
40224 for (i = 0, ii = esriJSONFeatures.length; i < ii; ++i) {
40225 features.push(this.readFeatureFromObject(esriJSONFeatures[i],
40226 options));
40227 }
40228 return features;
40229 } else {
40230 return [this.readFeatureFromObject(object, options)];
40231 }
40232};
40233
40234
40235/**
40236 * Read a geometry from a EsriJSON source.
40237 *
40238 * @function
40239 * @param {ArrayBuffer|Document|Node|Object|string} source Source.
40240 * @param {olx.format.ReadOptions=} opt_options Read options.
40241 * @return {ol.geom.Geometry} Geometry.
40242 * @api
40243 */
40244ol.format.EsriJSON.prototype.readGeometry;
40245
40246
40247/**
40248 * @inheritDoc
40249 */
40250ol.format.EsriJSON.prototype.readGeometryFromObject = function(
40251 object, opt_options) {
40252 return ol.format.EsriJSON.readGeometry_(
40253 /** @type {EsriJSONGeometry} */(object), opt_options);
40254};
40255
40256
40257/**
40258 * Read the projection from a EsriJSON source.
40259 *
40260 * @function
40261 * @param {ArrayBuffer|Document|Node|Object|string} source Source.
40262 * @return {ol.proj.Projection} Projection.
40263 * @api
40264 */
40265ol.format.EsriJSON.prototype.readProjection;
40266
40267
40268/**
40269 * @inheritDoc
40270 */
40271ol.format.EsriJSON.prototype.readProjectionFromObject = function(object) {
40272 var esriJSONObject = /** @type {EsriJSONObject} */ (object);
40273 if (esriJSONObject.spatialReference && esriJSONObject.spatialReference.wkid) {
40274 var crs = esriJSONObject.spatialReference.wkid;
40275 return ol.proj.get('EPSG:' + crs);
40276 } else {
40277 return null;
40278 }
40279};
40280
40281
40282/**
40283 * @param {ol.geom.Geometry} geometry Geometry.
40284 * @param {olx.format.WriteOptions=} opt_options Write options.
40285 * @private
40286 * @return {EsriJSONGeometry} EsriJSON geometry.
40287 */
40288ol.format.EsriJSON.writeGeometry_ = function(geometry, opt_options) {
40289 var geometryWriter = ol.format.EsriJSON.GEOMETRY_WRITERS_[geometry.getType()];
40290 return geometryWriter(/** @type {ol.geom.Geometry} */(
40291 ol.format.Feature.transformWithOptions(geometry, true, opt_options)),
40292 opt_options);
40293};
40294
40295
40296/**
40297 * Encode a geometry as a EsriJSON string.
40298 *
40299 * @function
40300 * @param {ol.geom.Geometry} geometry Geometry.
40301 * @param {olx.format.WriteOptions=} opt_options Write options.
40302 * @return {string} EsriJSON.
40303 * @api
40304 */
40305ol.format.EsriJSON.prototype.writeGeometry;
40306
40307
40308/**
40309 * Encode a geometry as a EsriJSON object.
40310 *
40311 * @param {ol.geom.Geometry} geometry Geometry.
40312 * @param {olx.format.WriteOptions=} opt_options Write options.
40313 * @return {EsriJSONGeometry} Object.
40314 * @override
40315 * @api
40316 */
40317ol.format.EsriJSON.prototype.writeGeometryObject = function(geometry,
40318 opt_options) {
40319 return ol.format.EsriJSON.writeGeometry_(geometry,
40320 this.adaptOptions(opt_options));
40321};
40322
40323
40324/**
40325 * Encode a feature as a EsriJSON Feature string.
40326 *
40327 * @function
40328 * @param {ol.Feature} feature Feature.
40329 * @param {olx.format.WriteOptions=} opt_options Write options.
40330 * @return {string} EsriJSON.
40331 * @api
40332 */
40333ol.format.EsriJSON.prototype.writeFeature;
40334
40335
40336/**
40337 * Encode a feature as a esriJSON Feature object.
40338 *
40339 * @param {ol.Feature} feature Feature.
40340 * @param {olx.format.WriteOptions=} opt_options Write options.
40341 * @return {Object} Object.
40342 * @override
40343 * @api
40344 */
40345ol.format.EsriJSON.prototype.writeFeatureObject = function(
40346 feature, opt_options) {
40347 opt_options = this.adaptOptions(opt_options);
40348 var object = {};
40349 var geometry = feature.getGeometry();
40350 if (geometry) {
40351 object['geometry'] =
40352 ol.format.EsriJSON.writeGeometry_(geometry, opt_options);
40353 if (opt_options && opt_options.featureProjection) {
40354 object['geometry']['spatialReference'] = /** @type {EsriJSONCRS} */({
40355 wkid: ol.proj.get(
40356 opt_options.featureProjection).getCode().split(':').pop()
40357 });
40358 }
40359 }
40360 var properties = feature.getProperties();
40361 delete properties[feature.getGeometryName()];
40362 if (!ol.obj.isEmpty(properties)) {
40363 object['attributes'] = properties;
40364 } else {
40365 object['attributes'] = {};
40366 }
40367 return object;
40368};
40369
40370
40371/**
40372 * Encode an array of features as EsriJSON.
40373 *
40374 * @function
40375 * @param {Array.<ol.Feature>} features Features.
40376 * @param {olx.format.WriteOptions=} opt_options Write options.
40377 * @return {string} EsriJSON.
40378 * @api
40379 */
40380ol.format.EsriJSON.prototype.writeFeatures;
40381
40382
40383/**
40384 * Encode an array of features as a EsriJSON object.
40385 *
40386 * @param {Array.<ol.Feature>} features Features.
40387 * @param {olx.format.WriteOptions=} opt_options Write options.
40388 * @return {Object} EsriJSON Object.
40389 * @override
40390 * @api
40391 */
40392ol.format.EsriJSON.prototype.writeFeaturesObject = function(features, opt_options) {
40393 opt_options = this.adaptOptions(opt_options);
40394 var objects = [];
40395 var i, ii;
40396 for (i = 0, ii = features.length; i < ii; ++i) {
40397 objects.push(this.writeFeatureObject(features[i], opt_options));
40398 }
40399 return /** @type {EsriJSONFeatureCollection} */ ({
40400 'features': objects
40401 });
40402};
40403
40404goog.provide('ol.format.filter.Filter');
40405
40406
40407/**
40408 * @classdesc
40409 * Abstract class; normally only used for creating subclasses and not instantiated in apps.
40410 * Base class for WFS GetFeature filters.
40411 *
40412 * @constructor
40413 * @param {!string} tagName The XML tag name for this filter.
40414 * @struct
40415 * @api
40416 */
40417ol.format.filter.Filter = function(tagName) {
40418
40419 /**
40420 * @private
40421 * @type {!string}
40422 */
40423 this.tagName_ = tagName;
40424};
40425
40426/**
40427 * The XML tag name for a filter.
40428 * @returns {!string} Name.
40429 */
40430ol.format.filter.Filter.prototype.getTagName = function() {
40431 return this.tagName_;
40432};
40433
40434goog.provide('ol.format.filter.LogicalNary');
40435
40436goog.require('ol');
40437goog.require('ol.asserts');
40438goog.require('ol.format.filter.Filter');
40439
40440
40441/**
40442 * @classdesc
40443 * Abstract class; normally only used for creating subclasses and not instantiated in apps.
40444 * Base class for WFS GetFeature n-ary logical filters.
40445 *
40446 * @constructor
40447 * @param {!string} tagName The XML tag name for this filter.
40448 * @param {...ol.format.filter.Filter} conditions Conditions.
40449 * @extends {ol.format.filter.Filter}
40450 */
40451ol.format.filter.LogicalNary = function(tagName, conditions) {
40452
40453 ol.format.filter.Filter.call(this, tagName);
40454
40455 /**
40456 * @public
40457 * @type {Array.<ol.format.filter.Filter>}
40458 */
40459 this.conditions = Array.prototype.slice.call(arguments, 1);
40460 ol.asserts.assert(this.conditions.length >= 2, 57); // At least 2 conditions are required.
40461};
40462ol.inherits(ol.format.filter.LogicalNary, ol.format.filter.Filter);
40463
40464goog.provide('ol.format.filter.And');
40465
40466goog.require('ol');
40467goog.require('ol.format.filter.LogicalNary');
40468
40469/**
40470 * @classdesc
40471 * Represents a logical `<And>` operator between two or more filter conditions.
40472 *
40473 * @constructor
40474 * @param {...ol.format.filter.Filter} conditions Conditions.
40475 * @extends {ol.format.filter.LogicalNary}
40476 * @api
40477 */
40478ol.format.filter.And = function(conditions) {
40479 var params = ['And'].concat(Array.prototype.slice.call(arguments));
40480 ol.format.filter.LogicalNary.apply(this, params);
40481};
40482ol.inherits(ol.format.filter.And, ol.format.filter.LogicalNary);
40483
40484goog.provide('ol.format.filter.Bbox');
40485
40486goog.require('ol');
40487goog.require('ol.format.filter.Filter');
40488
40489
40490/**
40491 * @classdesc
40492 * Represents a `<BBOX>` operator to test whether a geometry-valued property
40493 * intersects a fixed bounding box
40494 *
40495 * @constructor
40496 * @param {!string} geometryName Geometry name to use.
40497 * @param {!ol.Extent} extent Extent.
40498 * @param {string=} opt_srsName SRS name. No srsName attribute will be
40499 * set on geometries when this is not provided.
40500 * @extends {ol.format.filter.Filter}
40501 * @api
40502 */
40503ol.format.filter.Bbox = function(geometryName, extent, opt_srsName) {
40504
40505 ol.format.filter.Filter.call(this, 'BBOX');
40506
40507 /**
40508 * @public
40509 * @type {!string}
40510 */
40511 this.geometryName = geometryName;
40512
40513 /**
40514 * @public
40515 * @type {ol.Extent}
40516 */
40517 this.extent = extent;
40518
40519 /**
40520 * @public
40521 * @type {string|undefined}
40522 */
40523 this.srsName = opt_srsName;
40524};
40525ol.inherits(ol.format.filter.Bbox, ol.format.filter.Filter);
40526
40527goog.provide('ol.format.filter.Comparison');
40528
40529goog.require('ol');
40530goog.require('ol.format.filter.Filter');
40531
40532
40533/**
40534 * @classdesc
40535 * Abstract class; normally only used for creating subclasses and not instantiated in apps.
40536 * Base class for WFS GetFeature property comparison filters.
40537 *
40538 * @constructor
40539 * @param {!string} tagName The XML tag name for this filter.
40540 * @param {!string} propertyName Name of the context property to compare.
40541 * @extends {ol.format.filter.Filter}
40542 * @api
40543 */
40544ol.format.filter.Comparison = function(tagName, propertyName) {
40545
40546 ol.format.filter.Filter.call(this, tagName);
40547
40548 /**
40549 * @public
40550 * @type {!string}
40551 */
40552 this.propertyName = propertyName;
40553};
40554ol.inherits(ol.format.filter.Comparison, ol.format.filter.Filter);
40555
40556goog.provide('ol.format.filter.During');
40557
40558goog.require('ol');
40559goog.require('ol.format.filter.Comparison');
40560
40561
40562/**
40563 * @classdesc
40564 * Represents a `<During>` comparison operator.
40565 *
40566 * @constructor
40567 * @param {!string} propertyName Name of the context property to compare.
40568 * @param {!string} begin The begin date in ISO-8601 format.
40569 * @param {!string} end The end date in ISO-8601 format.
40570 * @extends {ol.format.filter.Comparison}
40571 * @api
40572 */
40573ol.format.filter.During = function(propertyName, begin, end) {
40574 ol.format.filter.Comparison.call(this, 'During', propertyName);
40575
40576 /**
40577 * @public
40578 * @type {!string}
40579 */
40580 this.begin = begin;
40581
40582 /**
40583 * @public
40584 * @type {!string}
40585 */
40586 this.end = end;
40587};
40588ol.inherits(ol.format.filter.During, ol.format.filter.Comparison);
40589
40590goog.provide('ol.format.filter.ComparisonBinary');
40591
40592goog.require('ol');
40593goog.require('ol.format.filter.Comparison');
40594
40595
40596/**
40597 * @classdesc
40598 * Abstract class; normally only used for creating subclasses and not instantiated in apps.
40599 * Base class for WFS GetFeature property binary comparison filters.
40600 *
40601 * @constructor
40602 * @param {!string} tagName The XML tag name for this filter.
40603 * @param {!string} propertyName Name of the context property to compare.
40604 * @param {!(string|number)} expression The value to compare.
40605 * @param {boolean=} opt_matchCase Case-sensitive?
40606 * @extends {ol.format.filter.Comparison}
40607 * @api
40608 */
40609ol.format.filter.ComparisonBinary = function(
40610 tagName, propertyName, expression, opt_matchCase) {
40611
40612 ol.format.filter.Comparison.call(this, tagName, propertyName);
40613
40614 /**
40615 * @public
40616 * @type {!(string|number)}
40617 */
40618 this.expression = expression;
40619
40620 /**
40621 * @public
40622 * @type {boolean|undefined}
40623 */
40624 this.matchCase = opt_matchCase;
40625};
40626ol.inherits(ol.format.filter.ComparisonBinary, ol.format.filter.Comparison);
40627
40628goog.provide('ol.format.filter.EqualTo');
40629
40630goog.require('ol');
40631goog.require('ol.format.filter.ComparisonBinary');
40632
40633
40634/**
40635 * @classdesc
40636 * Represents a `<PropertyIsEqualTo>` comparison operator.
40637 *
40638 * @constructor
40639 * @param {!string} propertyName Name of the context property to compare.
40640 * @param {!(string|number)} expression The value to compare.
40641 * @param {boolean=} opt_matchCase Case-sensitive?
40642 * @extends {ol.format.filter.ComparisonBinary}
40643 * @api
40644 */
40645ol.format.filter.EqualTo = function(propertyName, expression, opt_matchCase) {
40646 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsEqualTo', propertyName, expression, opt_matchCase);
40647};
40648ol.inherits(ol.format.filter.EqualTo, ol.format.filter.ComparisonBinary);
40649
40650goog.provide('ol.format.filter.GreaterThan');
40651
40652goog.require('ol');
40653goog.require('ol.format.filter.ComparisonBinary');
40654
40655
40656/**
40657 * @classdesc
40658 * Represents a `<PropertyIsGreaterThan>` comparison operator.
40659 *
40660 * @constructor
40661 * @param {!string} propertyName Name of the context property to compare.
40662 * @param {!number} expression The value to compare.
40663 * @extends {ol.format.filter.ComparisonBinary}
40664 * @api
40665 */
40666ol.format.filter.GreaterThan = function(propertyName, expression) {
40667 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThan', propertyName, expression);
40668};
40669ol.inherits(ol.format.filter.GreaterThan, ol.format.filter.ComparisonBinary);
40670
40671goog.provide('ol.format.filter.GreaterThanOrEqualTo');
40672
40673goog.require('ol');
40674goog.require('ol.format.filter.ComparisonBinary');
40675
40676
40677/**
40678 * @classdesc
40679 * Represents a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.
40680 *
40681 * @constructor
40682 * @param {!string} propertyName Name of the context property to compare.
40683 * @param {!number} expression The value to compare.
40684 * @extends {ol.format.filter.ComparisonBinary}
40685 * @api
40686 */
40687ol.format.filter.GreaterThanOrEqualTo = function(propertyName, expression) {
40688 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsGreaterThanOrEqualTo', propertyName, expression);
40689};
40690ol.inherits(ol.format.filter.GreaterThanOrEqualTo, ol.format.filter.ComparisonBinary);
40691
40692goog.provide('ol.format.filter.Spatial');
40693
40694goog.require('ol');
40695goog.require('ol.format.filter.Filter');
40696
40697
40698/**
40699 * @classdesc
40700 * Represents a spatial operator to test whether a geometry-valued property
40701 * relates to a given geometry.
40702 *
40703 * @constructor
40704 * @param {!string} tagName The XML tag name for this filter.
40705 * @param {!string} geometryName Geometry name to use.
40706 * @param {!ol.geom.Geometry} geometry Geometry.
40707 * @param {string=} opt_srsName SRS name. No srsName attribute will be
40708 * set on geometries when this is not provided.
40709 * @extends {ol.format.filter.Filter}
40710 * @api
40711 */
40712ol.format.filter.Spatial = function(tagName, geometryName, geometry, opt_srsName) {
40713
40714 ol.format.filter.Filter.call(this, tagName);
40715
40716 /**
40717 * @public
40718 * @type {!string}
40719 */
40720 this.geometryName = geometryName || 'the_geom';
40721
40722 /**
40723 * @public
40724 * @type {ol.geom.Geometry}
40725 */
40726 this.geometry = geometry;
40727
40728 /**
40729 * @public
40730 * @type {string|undefined}
40731 */
40732 this.srsName = opt_srsName;
40733};
40734ol.inherits(ol.format.filter.Spatial, ol.format.filter.Filter);
40735
40736goog.provide('ol.format.filter.Intersects');
40737
40738goog.require('ol');
40739goog.require('ol.format.filter.Spatial');
40740
40741
40742/**
40743 * @classdesc
40744 * Represents a `<Intersects>` operator to test whether a geometry-valued property
40745 * intersects a given geometry.
40746 *
40747 * @constructor
40748 * @param {!string} geometryName Geometry name to use.
40749 * @param {!ol.geom.Geometry} geometry Geometry.
40750 * @param {string=} opt_srsName SRS name. No srsName attribute will be
40751 * set on geometries when this is not provided.
40752 * @extends {ol.format.filter.Spatial}
40753 * @api
40754 */
40755ol.format.filter.Intersects = function(geometryName, geometry, opt_srsName) {
40756
40757 ol.format.filter.Spatial.call(this, 'Intersects', geometryName, geometry, opt_srsName);
40758
40759};
40760ol.inherits(ol.format.filter.Intersects, ol.format.filter.Spatial);
40761
40762goog.provide('ol.format.filter.IsBetween');
40763
40764goog.require('ol');
40765goog.require('ol.format.filter.Comparison');
40766
40767
40768/**
40769 * @classdesc
40770 * Represents a `<PropertyIsBetween>` comparison operator.
40771 *
40772 * @constructor
40773 * @param {!string} propertyName Name of the context property to compare.
40774 * @param {!number} lowerBoundary The lower bound of the range.
40775 * @param {!number} upperBoundary The upper bound of the range.
40776 * @extends {ol.format.filter.Comparison}
40777 * @api
40778 */
40779ol.format.filter.IsBetween = function(propertyName, lowerBoundary, upperBoundary) {
40780 ol.format.filter.Comparison.call(this, 'PropertyIsBetween', propertyName);
40781
40782 /**
40783 * @public
40784 * @type {!number}
40785 */
40786 this.lowerBoundary = lowerBoundary;
40787
40788 /**
40789 * @public
40790 * @type {!number}
40791 */
40792 this.upperBoundary = upperBoundary;
40793};
40794ol.inherits(ol.format.filter.IsBetween, ol.format.filter.Comparison);
40795
40796goog.provide('ol.format.filter.IsLike');
40797
40798goog.require('ol');
40799goog.require('ol.format.filter.Comparison');
40800
40801
40802/**
40803 * @classdesc
40804 * Represents a `<PropertyIsLike>` comparison operator.
40805 *
40806 * @constructor
40807 * @param {!string} propertyName Name of the context property to compare.
40808 * @param {!string} pattern Text pattern.
40809 * @param {string=} opt_wildCard Pattern character which matches any sequence of
40810 * zero or more string characters. Default is '*'.
40811 * @param {string=} opt_singleChar pattern character which matches any single
40812 * string character. Default is '.'.
40813 * @param {string=} opt_escapeChar Escape character which can be used to escape
40814 * the pattern characters. Default is '!'.
40815 * @param {boolean=} opt_matchCase Case-sensitive?
40816 * @extends {ol.format.filter.Comparison}
40817 * @api
40818 */
40819ol.format.filter.IsLike = function(propertyName, pattern,
40820 opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
40821 ol.format.filter.Comparison.call(this, 'PropertyIsLike', propertyName);
40822
40823 /**
40824 * @public
40825 * @type {!string}
40826 */
40827 this.pattern = pattern;
40828
40829 /**
40830 * @public
40831 * @type {!string}
40832 */
40833 this.wildCard = (opt_wildCard !== undefined) ? opt_wildCard : '*';
40834
40835 /**
40836 * @public
40837 * @type {!string}
40838 */
40839 this.singleChar = (opt_singleChar !== undefined) ? opt_singleChar : '.';
40840
40841 /**
40842 * @public
40843 * @type {!string}
40844 */
40845 this.escapeChar = (opt_escapeChar !== undefined) ? opt_escapeChar : '!';
40846
40847 /**
40848 * @public
40849 * @type {boolean|undefined}
40850 */
40851 this.matchCase = opt_matchCase;
40852};
40853ol.inherits(ol.format.filter.IsLike, ol.format.filter.Comparison);
40854
40855goog.provide('ol.format.filter.IsNull');
40856
40857goog.require('ol');
40858goog.require('ol.format.filter.Comparison');
40859
40860
40861/**
40862 * @classdesc
40863 * Represents a `<PropertyIsNull>` comparison operator.
40864 *
40865 * @constructor
40866 * @param {!string} propertyName Name of the context property to compare.
40867 * @extends {ol.format.filter.Comparison}
40868 * @api
40869 */
40870ol.format.filter.IsNull = function(propertyName) {
40871 ol.format.filter.Comparison.call(this, 'PropertyIsNull', propertyName);
40872};
40873ol.inherits(ol.format.filter.IsNull, ol.format.filter.Comparison);
40874
40875goog.provide('ol.format.filter.LessThan');
40876
40877goog.require('ol');
40878goog.require('ol.format.filter.ComparisonBinary');
40879
40880
40881/**
40882 * @classdesc
40883 * Represents a `<PropertyIsLessThan>` comparison operator.
40884 *
40885 * @constructor
40886 * @param {!string} propertyName Name of the context property to compare.
40887 * @param {!number} expression The value to compare.
40888 * @extends {ol.format.filter.ComparisonBinary}
40889 * @api
40890 */
40891ol.format.filter.LessThan = function(propertyName, expression) {
40892 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsLessThan', propertyName, expression);
40893};
40894ol.inherits(ol.format.filter.LessThan, ol.format.filter.ComparisonBinary);
40895
40896goog.provide('ol.format.filter.LessThanOrEqualTo');
40897
40898goog.require('ol');
40899goog.require('ol.format.filter.ComparisonBinary');
40900
40901
40902/**
40903 * @classdesc
40904 * Represents a `<PropertyIsLessThanOrEqualTo>` comparison operator.
40905 *
40906 * @constructor
40907 * @param {!string} propertyName Name of the context property to compare.
40908 * @param {!number} expression The value to compare.
40909 * @extends {ol.format.filter.ComparisonBinary}
40910 * @api
40911 */
40912ol.format.filter.LessThanOrEqualTo = function(propertyName, expression) {
40913 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsLessThanOrEqualTo', propertyName, expression);
40914};
40915ol.inherits(ol.format.filter.LessThanOrEqualTo, ol.format.filter.ComparisonBinary);
40916
40917goog.provide('ol.format.filter.Not');
40918
40919goog.require('ol');
40920goog.require('ol.format.filter.Filter');
40921
40922
40923/**
40924 * @classdesc
40925 * Represents a logical `<Not>` operator for a filter condition.
40926 *
40927 * @constructor
40928 * @param {!ol.format.filter.Filter} condition Filter condition.
40929 * @extends {ol.format.filter.Filter}
40930 * @api
40931 */
40932ol.format.filter.Not = function(condition) {
40933
40934 ol.format.filter.Filter.call(this, 'Not');
40935
40936 /**
40937 * @public
40938 * @type {!ol.format.filter.Filter}
40939 */
40940 this.condition = condition;
40941};
40942ol.inherits(ol.format.filter.Not, ol.format.filter.Filter);
40943
40944goog.provide('ol.format.filter.NotEqualTo');
40945
40946goog.require('ol');
40947goog.require('ol.format.filter.ComparisonBinary');
40948
40949
40950/**
40951 * @classdesc
40952 * Represents a `<PropertyIsNotEqualTo>` comparison operator.
40953 *
40954 * @constructor
40955 * @param {!string} propertyName Name of the context property to compare.
40956 * @param {!(string|number)} expression The value to compare.
40957 * @param {boolean=} opt_matchCase Case-sensitive?
40958 * @extends {ol.format.filter.ComparisonBinary}
40959 * @api
40960 */
40961ol.format.filter.NotEqualTo = function(propertyName, expression, opt_matchCase) {
40962 ol.format.filter.ComparisonBinary.call(this, 'PropertyIsNotEqualTo', propertyName, expression, opt_matchCase);
40963};
40964ol.inherits(ol.format.filter.NotEqualTo, ol.format.filter.ComparisonBinary);
40965
40966goog.provide('ol.format.filter.Or');
40967
40968goog.require('ol');
40969goog.require('ol.format.filter.LogicalNary');
40970
40971
40972/**
40973 * @classdesc
40974 * Represents a logical `<Or>` operator between two ore more filter conditions.
40975 *
40976 * @constructor
40977 * @param {...ol.format.filter.Filter} conditions Conditions.
40978 * @extends {ol.format.filter.LogicalNary}
40979 * @api
40980 */
40981ol.format.filter.Or = function(conditions) {
40982 var params = ['Or'].concat(Array.prototype.slice.call(arguments));
40983 ol.format.filter.LogicalNary.apply(this, params);
40984};
40985ol.inherits(ol.format.filter.Or, ol.format.filter.LogicalNary);
40986
40987goog.provide('ol.format.filter.Within');
40988
40989goog.require('ol');
40990goog.require('ol.format.filter.Spatial');
40991
40992
40993/**
40994 * @classdesc
40995 * Represents a `<Within>` operator to test whether a geometry-valued property
40996 * is within a given geometry.
40997 *
40998 * @constructor
40999 * @param {!string} geometryName Geometry name to use.
41000 * @param {!ol.geom.Geometry} geometry Geometry.
41001 * @param {string=} opt_srsName SRS name. No srsName attribute will be
41002 * set on geometries when this is not provided.
41003 * @extends {ol.format.filter.Spatial}
41004 * @api
41005 */
41006ol.format.filter.Within = function(geometryName, geometry, opt_srsName) {
41007
41008 ol.format.filter.Spatial.call(this, 'Within', geometryName, geometry, opt_srsName);
41009
41010};
41011ol.inherits(ol.format.filter.Within, ol.format.filter.Spatial);
41012
41013goog.provide('ol.format.filter');
41014
41015goog.require('ol.format.filter.And');
41016goog.require('ol.format.filter.Bbox');
41017goog.require('ol.format.filter.During');
41018goog.require('ol.format.filter.EqualTo');
41019goog.require('ol.format.filter.GreaterThan');
41020goog.require('ol.format.filter.GreaterThanOrEqualTo');
41021goog.require('ol.format.filter.Intersects');
41022goog.require('ol.format.filter.IsBetween');
41023goog.require('ol.format.filter.IsLike');
41024goog.require('ol.format.filter.IsNull');
41025goog.require('ol.format.filter.LessThan');
41026goog.require('ol.format.filter.LessThanOrEqualTo');
41027goog.require('ol.format.filter.Not');
41028goog.require('ol.format.filter.NotEqualTo');
41029goog.require('ol.format.filter.Or');
41030goog.require('ol.format.filter.Within');
41031
41032
41033/**
41034 * Create a logical `<And>` operator between two or more filter conditions.
41035 *
41036 * @param {...ol.format.filter.Filter} conditions Filter conditions.
41037 * @returns {!ol.format.filter.And} `<And>` operator.
41038 * @api
41039 */
41040ol.format.filter.and = function(conditions) {
41041 var params = [null].concat(Array.prototype.slice.call(arguments));
41042 return new (Function.prototype.bind.apply(ol.format.filter.And, params));
41043};
41044
41045
41046/**
41047 * Create a logical `<Or>` operator between two or more filter conditions.
41048 *
41049 * @param {...ol.format.filter.Filter} conditions Filter conditions.
41050 * @returns {!ol.format.filter.Or} `<Or>` operator.
41051 * @api
41052 */
41053ol.format.filter.or = function(conditions) {
41054 var params = [null].concat(Array.prototype.slice.call(arguments));
41055 return new (Function.prototype.bind.apply(ol.format.filter.Or, params));
41056};
41057
41058
41059/**
41060 * Represents a logical `<Not>` operator for a filter condition.
41061 *
41062 * @param {!ol.format.filter.Filter} condition Filter condition.
41063 * @returns {!ol.format.filter.Not} `<Not>` operator.
41064 * @api
41065 */
41066ol.format.filter.not = function(condition) {
41067 return new ol.format.filter.Not(condition);
41068};
41069
41070
41071/**
41072 * Create a `<BBOX>` operator to test whether a geometry-valued property
41073 * intersects a fixed bounding box
41074 *
41075 * @param {!string} geometryName Geometry name to use.
41076 * @param {!ol.Extent} extent Extent.
41077 * @param {string=} opt_srsName SRS name. No srsName attribute will be
41078 * set on geometries when this is not provided.
41079 * @returns {!ol.format.filter.Bbox} `<BBOX>` operator.
41080 * @api
41081 */
41082ol.format.filter.bbox = function(geometryName, extent, opt_srsName) {
41083 return new ol.format.filter.Bbox(geometryName, extent, opt_srsName);
41084};
41085
41086/**
41087 * Create a `<Intersects>` operator to test whether a geometry-valued property
41088 * intersects a given geometry.
41089 *
41090 * @param {!string} geometryName Geometry name to use.
41091 * @param {!ol.geom.Geometry} geometry Geometry.
41092 * @param {string=} opt_srsName SRS name. No srsName attribute will be
41093 * set on geometries when this is not provided.
41094 * @returns {!ol.format.filter.Intersects} `<Intersects>` operator.
41095 * @api
41096 */
41097ol.format.filter.intersects = function(geometryName, geometry, opt_srsName) {
41098 return new ol.format.filter.Intersects(geometryName, geometry, opt_srsName);
41099};
41100
41101/**
41102 * Create a `<Within>` operator to test whether a geometry-valued property
41103 * is within a given geometry.
41104 *
41105 * @param {!string} geometryName Geometry name to use.
41106 * @param {!ol.geom.Geometry} geometry Geometry.
41107 * @param {string=} opt_srsName SRS name. No srsName attribute will be
41108 * set on geometries when this is not provided.
41109 * @returns {!ol.format.filter.Within} `<Within>` operator.
41110 * @api
41111 */
41112ol.format.filter.within = function(geometryName, geometry, opt_srsName) {
41113 return new ol.format.filter.Within(geometryName, geometry, opt_srsName);
41114};
41115
41116
41117/**
41118 * Creates a `<PropertyIsEqualTo>` comparison operator.
41119 *
41120 * @param {!string} propertyName Name of the context property to compare.
41121 * @param {!(string|number)} expression The value to compare.
41122 * @param {boolean=} opt_matchCase Case-sensitive?
41123 * @returns {!ol.format.filter.EqualTo} `<PropertyIsEqualTo>` operator.
41124 * @api
41125 */
41126ol.format.filter.equalTo = function(propertyName, expression, opt_matchCase) {
41127 return new ol.format.filter.EqualTo(propertyName, expression, opt_matchCase);
41128};
41129
41130
41131/**
41132 * Creates a `<PropertyIsNotEqualTo>` comparison operator.
41133 *
41134 * @param {!string} propertyName Name of the context property to compare.
41135 * @param {!(string|number)} expression The value to compare.
41136 * @param {boolean=} opt_matchCase Case-sensitive?
41137 * @returns {!ol.format.filter.NotEqualTo} `<PropertyIsNotEqualTo>` operator.
41138 * @api
41139 */
41140ol.format.filter.notEqualTo = function(propertyName, expression, opt_matchCase) {
41141 return new ol.format.filter.NotEqualTo(propertyName, expression, opt_matchCase);
41142};
41143
41144
41145/**
41146 * Creates a `<PropertyIsLessThan>` comparison operator.
41147 *
41148 * @param {!string} propertyName Name of the context property to compare.
41149 * @param {!number} expression The value to compare.
41150 * @returns {!ol.format.filter.LessThan} `<PropertyIsLessThan>` operator.
41151 * @api
41152 */
41153ol.format.filter.lessThan = function(propertyName, expression) {
41154 return new ol.format.filter.LessThan(propertyName, expression);
41155};
41156
41157
41158/**
41159 * Creates a `<PropertyIsLessThanOrEqualTo>` comparison operator.
41160 *
41161 * @param {!string} propertyName Name of the context property to compare.
41162 * @param {!number} expression The value to compare.
41163 * @returns {!ol.format.filter.LessThanOrEqualTo} `<PropertyIsLessThanOrEqualTo>` operator.
41164 * @api
41165 */
41166ol.format.filter.lessThanOrEqualTo = function(propertyName, expression) {
41167 return new ol.format.filter.LessThanOrEqualTo(propertyName, expression);
41168};
41169
41170
41171/**
41172 * Creates a `<PropertyIsGreaterThan>` comparison operator.
41173 *
41174 * @param {!string} propertyName Name of the context property to compare.
41175 * @param {!number} expression The value to compare.
41176 * @returns {!ol.format.filter.GreaterThan} `<PropertyIsGreaterThan>` operator.
41177 * @api
41178 */
41179ol.format.filter.greaterThan = function(propertyName, expression) {
41180 return new ol.format.filter.GreaterThan(propertyName, expression);
41181};
41182
41183
41184/**
41185 * Creates a `<PropertyIsGreaterThanOrEqualTo>` comparison operator.
41186 *
41187 * @param {!string} propertyName Name of the context property to compare.
41188 * @param {!number} expression The value to compare.
41189 * @returns {!ol.format.filter.GreaterThanOrEqualTo} `<PropertyIsGreaterThanOrEqualTo>` operator.
41190 * @api
41191 */
41192ol.format.filter.greaterThanOrEqualTo = function(propertyName, expression) {
41193 return new ol.format.filter.GreaterThanOrEqualTo(propertyName, expression);
41194};
41195
41196
41197/**
41198 * Creates a `<PropertyIsNull>` comparison operator to test whether a property value
41199 * is null.
41200 *
41201 * @param {!string} propertyName Name of the context property to compare.
41202 * @returns {!ol.format.filter.IsNull} `<PropertyIsNull>` operator.
41203 * @api
41204 */
41205ol.format.filter.isNull = function(propertyName) {
41206 return new ol.format.filter.IsNull(propertyName);
41207};
41208
41209
41210/**
41211 * Creates a `<PropertyIsBetween>` comparison operator to test whether an expression
41212 * value lies within a range given by a lower and upper bound (inclusive).
41213 *
41214 * @param {!string} propertyName Name of the context property to compare.
41215 * @param {!number} lowerBoundary The lower bound of the range.
41216 * @param {!number} upperBoundary The upper bound of the range.
41217 * @returns {!ol.format.filter.IsBetween} `<PropertyIsBetween>` operator.
41218 * @api
41219 */
41220ol.format.filter.between = function(propertyName, lowerBoundary, upperBoundary) {
41221 return new ol.format.filter.IsBetween(propertyName, lowerBoundary, upperBoundary);
41222};
41223
41224
41225/**
41226 * Represents a `<PropertyIsLike>` comparison operator that matches a string property
41227 * value against a text pattern.
41228 *
41229 * @param {!string} propertyName Name of the context property to compare.
41230 * @param {!string} pattern Text pattern.
41231 * @param {string=} opt_wildCard Pattern character which matches any sequence of
41232 * zero or more string characters. Default is '*'.
41233 * @param {string=} opt_singleChar pattern character which matches any single
41234 * string character. Default is '.'.
41235 * @param {string=} opt_escapeChar Escape character which can be used to escape
41236 * the pattern characters. Default is '!'.
41237 * @param {boolean=} opt_matchCase Case-sensitive?
41238 * @returns {!ol.format.filter.IsLike} `<PropertyIsLike>` operator.
41239 * @api
41240 */
41241ol.format.filter.like = function(propertyName, pattern,
41242 opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase) {
41243 return new ol.format.filter.IsLike(propertyName, pattern,
41244 opt_wildCard, opt_singleChar, opt_escapeChar, opt_matchCase);
41245};
41246
41247
41248/**
41249 * Create a `<During>` temporal operator.
41250 *
41251 * @param {!string} propertyName Name of the context property to compare.
41252 * @param {!string} begin The begin date in ISO-8601 format.
41253 * @param {!string} end The end date in ISO-8601 format.
41254 * @returns {!ol.format.filter.During} `<During>` operator.
41255 * @api
41256 */
41257ol.format.filter.during = function(propertyName, begin, end) {
41258 return new ol.format.filter.During(propertyName, begin, end);
41259};
41260
41261goog.provide('ol.geom.GeometryCollection');
41262
41263goog.require('ol');
41264goog.require('ol.events');
41265goog.require('ol.events.EventType');
41266goog.require('ol.extent');
41267goog.require('ol.geom.Geometry');
41268goog.require('ol.geom.GeometryType');
41269goog.require('ol.obj');
41270
41271
41272/**
41273 * @classdesc
41274 * An array of {@link ol.geom.Geometry} objects.
41275 *
41276 * @constructor
41277 * @extends {ol.geom.Geometry}
41278 * @param {Array.<ol.geom.Geometry>=} opt_geometries Geometries.
41279 * @api
41280 */
41281ol.geom.GeometryCollection = function(opt_geometries) {
41282
41283 ol.geom.Geometry.call(this);
41284
41285 /**
41286 * @private
41287 * @type {Array.<ol.geom.Geometry>}
41288 */
41289 this.geometries_ = opt_geometries ? opt_geometries : null;
41290
41291 this.listenGeometriesChange_();
41292};
41293ol.inherits(ol.geom.GeometryCollection, ol.geom.Geometry);
41294
41295
41296/**
41297 * @param {Array.<ol.geom.Geometry>} geometries Geometries.
41298 * @private
41299 * @return {Array.<ol.geom.Geometry>} Cloned geometries.
41300 */
41301ol.geom.GeometryCollection.cloneGeometries_ = function(geometries) {
41302 var clonedGeometries = [];
41303 var i, ii;
41304 for (i = 0, ii = geometries.length; i < ii; ++i) {
41305 clonedGeometries.push(geometries[i].clone());
41306 }
41307 return clonedGeometries;
41308};
41309
41310
41311/**
41312 * @private
41313 */
41314ol.geom.GeometryCollection.prototype.unlistenGeometriesChange_ = function() {
41315 var i, ii;
41316 if (!this.geometries_) {
41317 return;
41318 }
41319 for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
41320 ol.events.unlisten(
41321 this.geometries_[i], ol.events.EventType.CHANGE,
41322 this.changed, this);
41323 }
41324};
41325
41326
41327/**
41328 * @private
41329 */
41330ol.geom.GeometryCollection.prototype.listenGeometriesChange_ = function() {
41331 var i, ii;
41332 if (!this.geometries_) {
41333 return;
41334 }
41335 for (i = 0, ii = this.geometries_.length; i < ii; ++i) {
41336 ol.events.listen(
41337 this.geometries_[i], ol.events.EventType.CHANGE,
41338 this.changed, this);
41339 }
41340};
41341
41342
41343/**
41344 * Make a complete copy of the geometry.
41345 * @return {!ol.geom.GeometryCollection} Clone.
41346 * @override
41347 * @api
41348 */
41349ol.geom.GeometryCollection.prototype.clone = function() {
41350 var geometryCollection = new ol.geom.GeometryCollection(null);
41351 geometryCollection.setGeometries(this.geometries_);
41352 return geometryCollection;
41353};
41354
41355
41356/**
41357 * @inheritDoc
41358 */
41359ol.geom.GeometryCollection.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
41360 if (minSquaredDistance <
41361 ol.extent.closestSquaredDistanceXY(this.getExtent(), x, y)) {
41362 return minSquaredDistance;
41363 }
41364 var geometries = this.geometries_;
41365 var i, ii;
41366 for (i = 0, ii = geometries.length; i < ii; ++i) {
41367 minSquaredDistance = geometries[i].closestPointXY(
41368 x, y, closestPoint, minSquaredDistance);
41369 }
41370 return minSquaredDistance;
41371};
41372
41373
41374/**
41375 * @inheritDoc
41376 */
41377ol.geom.GeometryCollection.prototype.containsXY = function(x, y) {
41378 var geometries = this.geometries_;
41379 var i, ii;
41380 for (i = 0, ii = geometries.length; i < ii; ++i) {
41381 if (geometries[i].containsXY(x, y)) {
41382 return true;
41383 }
41384 }
41385 return false;
41386};
41387
41388
41389/**
41390 * @inheritDoc
41391 */
41392ol.geom.GeometryCollection.prototype.computeExtent = function(extent) {
41393 ol.extent.createOrUpdateEmpty(extent);
41394 var geometries = this.geometries_;
41395 for (var i = 0, ii = geometries.length; i < ii; ++i) {
41396 ol.extent.extend(extent, geometries[i].getExtent());
41397 }
41398 return extent;
41399};
41400
41401
41402/**
41403 * Return the geometries that make up this geometry collection.
41404 * @return {Array.<ol.geom.Geometry>} Geometries.
41405 * @api
41406 */
41407ol.geom.GeometryCollection.prototype.getGeometries = function() {
41408 return ol.geom.GeometryCollection.cloneGeometries_(this.geometries_);
41409};
41410
41411
41412/**
41413 * @return {Array.<ol.geom.Geometry>} Geometries.
41414 */
41415ol.geom.GeometryCollection.prototype.getGeometriesArray = function() {
41416 return this.geometries_;
41417};
41418
41419
41420/**
41421 * @inheritDoc
41422 */
41423ol.geom.GeometryCollection.prototype.getSimplifiedGeometry = function(squaredTolerance) {
41424 if (this.simplifiedGeometryRevision != this.getRevision()) {
41425 ol.obj.clear(this.simplifiedGeometryCache);
41426 this.simplifiedGeometryMaxMinSquaredTolerance = 0;
41427 this.simplifiedGeometryRevision = this.getRevision();
41428 }
41429 if (squaredTolerance < 0 ||
41430 (this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
41431 squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)) {
41432 return this;
41433 }
41434 var key = squaredTolerance.toString();
41435 if (this.simplifiedGeometryCache.hasOwnProperty(key)) {
41436 return this.simplifiedGeometryCache[key];
41437 } else {
41438 var simplifiedGeometries = [];
41439 var geometries = this.geometries_;
41440 var simplified = false;
41441 var i, ii;
41442 for (i = 0, ii = geometries.length; i < ii; ++i) {
41443 var geometry = geometries[i];
41444 var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
41445 simplifiedGeometries.push(simplifiedGeometry);
41446 if (simplifiedGeometry !== geometry) {
41447 simplified = true;
41448 }
41449 }
41450 if (simplified) {
41451 var simplifiedGeometryCollection = new ol.geom.GeometryCollection(null);
41452 simplifiedGeometryCollection.setGeometriesArray(simplifiedGeometries);
41453 this.simplifiedGeometryCache[key] = simplifiedGeometryCollection;
41454 return simplifiedGeometryCollection;
41455 } else {
41456 this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
41457 return this;
41458 }
41459 }
41460};
41461
41462
41463/**
41464 * @inheritDoc
41465 * @api
41466 */
41467ol.geom.GeometryCollection.prototype.getType = function() {
41468 return ol.geom.GeometryType.GEOMETRY_COLLECTION;
41469};
41470
41471
41472/**
41473 * @inheritDoc
41474 * @api
41475 */
41476ol.geom.GeometryCollection.prototype.intersectsExtent = function(extent) {
41477 var geometries = this.geometries_;
41478 var i, ii;
41479 for (i = 0, ii = geometries.length; i < ii; ++i) {
41480 if (geometries[i].intersectsExtent(extent)) {
41481 return true;
41482 }
41483 }
41484 return false;
41485};
41486
41487
41488/**
41489 * @return {boolean} Is empty.
41490 */
41491ol.geom.GeometryCollection.prototype.isEmpty = function() {
41492 return this.geometries_.length === 0;
41493};
41494
41495
41496/**
41497 * @inheritDoc
41498 * @api
41499 */
41500ol.geom.GeometryCollection.prototype.rotate = function(angle, anchor) {
41501 var geometries = this.geometries_;
41502 for (var i = 0, ii = geometries.length; i < ii; ++i) {
41503 geometries[i].rotate(angle, anchor);
41504 }
41505 this.changed();
41506};
41507
41508
41509/**
41510 * @inheritDoc
41511 * @api
41512 */
41513ol.geom.GeometryCollection.prototype.scale = function(sx, opt_sy, opt_anchor) {
41514 var anchor = opt_anchor;
41515 if (!anchor) {
41516 anchor = ol.extent.getCenter(this.getExtent());
41517 }
41518 var geometries = this.geometries_;
41519 for (var i = 0, ii = geometries.length; i < ii; ++i) {
41520 geometries[i].scale(sx, opt_sy, anchor);
41521 }
41522 this.changed();
41523};
41524
41525
41526/**
41527 * Set the geometries that make up this geometry collection.
41528 * @param {Array.<ol.geom.Geometry>} geometries Geometries.
41529 * @api
41530 */
41531ol.geom.GeometryCollection.prototype.setGeometries = function(geometries) {
41532 this.setGeometriesArray(
41533 ol.geom.GeometryCollection.cloneGeometries_(geometries));
41534};
41535
41536
41537/**
41538 * @param {Array.<ol.geom.Geometry>} geometries Geometries.
41539 */
41540ol.geom.GeometryCollection.prototype.setGeometriesArray = function(geometries) {
41541 this.unlistenGeometriesChange_();
41542 this.geometries_ = geometries;
41543 this.listenGeometriesChange_();
41544 this.changed();
41545};
41546
41547
41548/**
41549 * @inheritDoc
41550 * @api
41551 */
41552ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) {
41553 var geometries = this.geometries_;
41554 var i, ii;
41555 for (i = 0, ii = geometries.length; i < ii; ++i) {
41556 geometries[i].applyTransform(transformFn);
41557 }
41558 this.changed();
41559};
41560
41561
41562/**
41563 * Translate the geometry.
41564 * @param {number} deltaX Delta X.
41565 * @param {number} deltaY Delta Y.
41566 * @override
41567 * @api
41568 */
41569ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) {
41570 var geometries = this.geometries_;
41571 var i, ii;
41572 for (i = 0, ii = geometries.length; i < ii; ++i) {
41573 geometries[i].translate(deltaX, deltaY);
41574 }
41575 this.changed();
41576};
41577
41578
41579/**
41580 * @inheritDoc
41581 */
41582ol.geom.GeometryCollection.prototype.disposeInternal = function() {
41583 this.unlistenGeometriesChange_();
41584 ol.geom.Geometry.prototype.disposeInternal.call(this);
41585};
41586
41587// TODO: serialize dataProjection as crs member when writing
41588// see https://github.com/openlayers/openlayers/issues/2078
41589
41590goog.provide('ol.format.GeoJSON');
41591
41592goog.require('ol');
41593goog.require('ol.asserts');
41594goog.require('ol.Feature');
41595goog.require('ol.format.Feature');
41596goog.require('ol.format.JSONFeature');
41597goog.require('ol.geom.GeometryCollection');
41598goog.require('ol.geom.LineString');
41599goog.require('ol.geom.MultiLineString');
41600goog.require('ol.geom.MultiPoint');
41601goog.require('ol.geom.MultiPolygon');
41602goog.require('ol.geom.Point');
41603goog.require('ol.geom.Polygon');
41604goog.require('ol.obj');
41605goog.require('ol.proj');
41606
41607
41608/**
41609 * @classdesc
41610 * Feature format for reading and writing data in the GeoJSON format.
41611 *
41612 * @constructor
41613 * @extends {ol.format.JSONFeature}
41614 * @param {olx.format.GeoJSONOptions=} opt_options Options.
41615 * @api
41616 */
41617ol.format.GeoJSON = function(opt_options) {
41618
41619 var options = opt_options ? opt_options : {};
41620
41621 ol.format.JSONFeature.call(this);
41622
41623 /**
41624 * @inheritDoc
41625 */
41626 this.defaultDataProjection = ol.proj.get(
41627 options.defaultDataProjection ?
41628 options.defaultDataProjection : 'EPSG:4326');
41629
41630
41631 if (options.featureProjection) {
41632 this.defaultFeatureProjection = ol.proj.get(options.featureProjection);
41633 }
41634
41635 /**
41636 * Name of the geometry attribute for features.
41637 * @type {string|undefined}
41638 * @private
41639 */
41640 this.geometryName_ = options.geometryName;
41641
41642};
41643ol.inherits(ol.format.GeoJSON, ol.format.JSONFeature);
41644
41645
41646/**
41647 * @param {GeoJSONGeometry|GeoJSONGeometryCollection} object Object.
41648 * @param {olx.format.ReadOptions=} opt_options Read options.
41649 * @private
41650 * @return {ol.geom.Geometry} Geometry.
41651 */
41652ol.format.GeoJSON.readGeometry_ = function(object, opt_options) {
41653 if (!object) {
41654 return null;
41655 }
41656 var geometryReader = ol.format.GeoJSON.GEOMETRY_READERS_[object.type];
41657 return /** @type {ol.geom.Geometry} */ (
41658 ol.format.Feature.transformWithOptions(
41659 geometryReader(object), false, opt_options));
41660};
41661
41662
41663/**
41664 * @param {GeoJSONGeometryCollection} object Object.
41665 * @param {olx.format.ReadOptions=} opt_options Read options.
41666 * @private
41667 * @return {ol.geom.GeometryCollection} Geometry collection.
41668 */
41669ol.format.GeoJSON.readGeometryCollectionGeometry_ = function(
41670 object, opt_options) {
41671 var geometries = object.geometries.map(
41672 /**
41673 * @param {GeoJSONGeometry} geometry Geometry.
41674 * @return {ol.geom.Geometry} geometry Geometry.
41675 */
41676 function(geometry) {
41677 return ol.format.GeoJSON.readGeometry_(geometry, opt_options);
41678 });
41679 return new ol.geom.GeometryCollection(geometries);
41680};
41681
41682
41683/**
41684 * @param {GeoJSONGeometry} object Object.
41685 * @private
41686 * @return {ol.geom.Point} Point.
41687 */
41688ol.format.GeoJSON.readPointGeometry_ = function(object) {
41689 return new ol.geom.Point(object.coordinates);
41690};
41691
41692
41693/**
41694 * @param {GeoJSONGeometry} object Object.
41695 * @private
41696 * @return {ol.geom.LineString} LineString.
41697 */
41698ol.format.GeoJSON.readLineStringGeometry_ = function(object) {
41699 return new ol.geom.LineString(object.coordinates);
41700};
41701
41702
41703/**
41704 * @param {GeoJSONGeometry} object Object.
41705 * @private
41706 * @return {ol.geom.MultiLineString} MultiLineString.
41707 */
41708ol.format.GeoJSON.readMultiLineStringGeometry_ = function(object) {
41709 return new ol.geom.MultiLineString(object.coordinates);
41710};
41711
41712
41713/**
41714 * @param {GeoJSONGeometry} object Object.
41715 * @private
41716 * @return {ol.geom.MultiPoint} MultiPoint.
41717 */
41718ol.format.GeoJSON.readMultiPointGeometry_ = function(object) {
41719 return new ol.geom.MultiPoint(object.coordinates);
41720};
41721
41722
41723/**
41724 * @param {GeoJSONGeometry} object Object.
41725 * @private
41726 * @return {ol.geom.MultiPolygon} MultiPolygon.
41727 */
41728ol.format.GeoJSON.readMultiPolygonGeometry_ = function(object) {
41729 return new ol.geom.MultiPolygon(object.coordinates);
41730};
41731
41732
41733/**
41734 * @param {GeoJSONGeometry} object Object.
41735 * @private
41736 * @return {ol.geom.Polygon} Polygon.
41737 */
41738ol.format.GeoJSON.readPolygonGeometry_ = function(object) {
41739 return new ol.geom.Polygon(object.coordinates);
41740};
41741
41742
41743/**
41744 * @param {ol.geom.Geometry} geometry Geometry.
41745 * @param {olx.format.WriteOptions=} opt_options Write options.
41746 * @private
41747 * @return {GeoJSONGeometry|GeoJSONGeometryCollection} GeoJSON geometry.
41748 */
41749ol.format.GeoJSON.writeGeometry_ = function(geometry, opt_options) {
41750 var geometryWriter = ol.format.GeoJSON.GEOMETRY_WRITERS_[geometry.getType()];
41751 return geometryWriter(/** @type {ol.geom.Geometry} */ (
41752 ol.format.Feature.transformWithOptions(geometry, true, opt_options)),
41753 opt_options);
41754};
41755
41756
41757/**
41758 * @param {ol.geom.Geometry} geometry Geometry.
41759 * @private
41760 * @return {GeoJSONGeometryCollection} Empty GeoJSON geometry collection.
41761 */
41762ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_ = function(geometry) {
41763 return /** @type {GeoJSONGeometryCollection} */ ({
41764 type: 'GeometryCollection',
41765 geometries: []
41766 });
41767};
41768
41769
41770/**
41771 * @param {ol.geom.GeometryCollection} geometry Geometry.
41772 * @param {olx.format.WriteOptions=} opt_options Write options.
41773 * @private
41774 * @return {GeoJSONGeometryCollection} GeoJSON geometry collection.
41775 */
41776ol.format.GeoJSON.writeGeometryCollectionGeometry_ = function(
41777 geometry, opt_options) {
41778 var geometries = geometry.getGeometriesArray().map(function(geometry) {
41779 var options = ol.obj.assign({}, opt_options);
41780 delete options.featureProjection;
41781 return ol.format.GeoJSON.writeGeometry_(geometry, options);
41782 });
41783 return /** @type {GeoJSONGeometryCollection} */ ({
41784 type: 'GeometryCollection',
41785 geometries: geometries
41786 });
41787};
41788
41789
41790/**
41791 * @param {ol.geom.LineString} geometry Geometry.
41792 * @param {olx.format.WriteOptions=} opt_options Write options.
41793 * @private
41794 * @return {GeoJSONGeometry} GeoJSON geometry.
41795 */
41796ol.format.GeoJSON.writeLineStringGeometry_ = function(geometry, opt_options) {
41797 return /** @type {GeoJSONGeometry} */ ({
41798 type: 'LineString',
41799 coordinates: geometry.getCoordinates()
41800 });
41801};
41802
41803
41804/**
41805 * @param {ol.geom.MultiLineString} geometry Geometry.
41806 * @param {olx.format.WriteOptions=} opt_options Write options.
41807 * @private
41808 * @return {GeoJSONGeometry} GeoJSON geometry.
41809 */
41810ol.format.GeoJSON.writeMultiLineStringGeometry_ = function(geometry, opt_options) {
41811 return /** @type {GeoJSONGeometry} */ ({
41812 type: 'MultiLineString',
41813 coordinates: geometry.getCoordinates()
41814 });
41815};
41816
41817
41818/**
41819 * @param {ol.geom.MultiPoint} geometry Geometry.
41820 * @param {olx.format.WriteOptions=} opt_options Write options.
41821 * @private
41822 * @return {GeoJSONGeometry} GeoJSON geometry.
41823 */
41824ol.format.GeoJSON.writeMultiPointGeometry_ = function(geometry, opt_options) {
41825 return /** @type {GeoJSONGeometry} */ ({
41826 type: 'MultiPoint',
41827 coordinates: geometry.getCoordinates()
41828 });
41829};
41830
41831
41832/**
41833 * @param {ol.geom.MultiPolygon} geometry Geometry.
41834 * @param {olx.format.WriteOptions=} opt_options Write options.
41835 * @private
41836 * @return {GeoJSONGeometry} GeoJSON geometry.
41837 */
41838ol.format.GeoJSON.writeMultiPolygonGeometry_ = function(geometry, opt_options) {
41839 var right;
41840 if (opt_options) {
41841 right = opt_options.rightHanded;
41842 }
41843 return /** @type {GeoJSONGeometry} */ ({
41844 type: 'MultiPolygon',
41845 coordinates: geometry.getCoordinates(right)
41846 });
41847};
41848
41849
41850/**
41851 * @param {ol.geom.Point} geometry Geometry.
41852 * @param {olx.format.WriteOptions=} opt_options Write options.
41853 * @private
41854 * @return {GeoJSONGeometry} GeoJSON geometry.
41855 */
41856ol.format.GeoJSON.writePointGeometry_ = function(geometry, opt_options) {
41857 return /** @type {GeoJSONGeometry} */ ({
41858 type: 'Point',
41859 coordinates: geometry.getCoordinates()
41860 });
41861};
41862
41863
41864/**
41865 * @param {ol.geom.Polygon} geometry Geometry.
41866 * @param {olx.format.WriteOptions=} opt_options Write options.
41867 * @private
41868 * @return {GeoJSONGeometry} GeoJSON geometry.
41869 */
41870ol.format.GeoJSON.writePolygonGeometry_ = function(geometry, opt_options) {
41871 var right;
41872 if (opt_options) {
41873 right = opt_options.rightHanded;
41874 }
41875 return /** @type {GeoJSONGeometry} */ ({
41876 type: 'Polygon',
41877 coordinates: geometry.getCoordinates(right)
41878 });
41879};
41880
41881
41882/**
41883 * @const
41884 * @private
41885 * @type {Object.<string, function(GeoJSONObject): ol.geom.Geometry>}
41886 */
41887ol.format.GeoJSON.GEOMETRY_READERS_ = {
41888 'Point': ol.format.GeoJSON.readPointGeometry_,
41889 'LineString': ol.format.GeoJSON.readLineStringGeometry_,
41890 'Polygon': ol.format.GeoJSON.readPolygonGeometry_,
41891 'MultiPoint': ol.format.GeoJSON.readMultiPointGeometry_,
41892 'MultiLineString': ol.format.GeoJSON.readMultiLineStringGeometry_,
41893 'MultiPolygon': ol.format.GeoJSON.readMultiPolygonGeometry_,
41894 'GeometryCollection': ol.format.GeoJSON.readGeometryCollectionGeometry_
41895};
41896
41897
41898/**
41899 * @const
41900 * @private
41901 * @type {Object.<string, function(ol.geom.Geometry, olx.format.WriteOptions=): (GeoJSONGeometry|GeoJSONGeometryCollection)>}
41902 */
41903ol.format.GeoJSON.GEOMETRY_WRITERS_ = {
41904 'Point': ol.format.GeoJSON.writePointGeometry_,
41905 'LineString': ol.format.GeoJSON.writeLineStringGeometry_,
41906 'Polygon': ol.format.GeoJSON.writePolygonGeometry_,
41907 'MultiPoint': ol.format.GeoJSON.writeMultiPointGeometry_,
41908 'MultiLineString': ol.format.GeoJSON.writeMultiLineStringGeometry_,
41909 'MultiPolygon': ol.format.GeoJSON.writeMultiPolygonGeometry_,
41910 'GeometryCollection': ol.format.GeoJSON.writeGeometryCollectionGeometry_,
41911 'Circle': ol.format.GeoJSON.writeEmptyGeometryCollectionGeometry_
41912};
41913
41914
41915/**
41916 * Read a feature from a GeoJSON Feature source. Only works for Feature or
41917 * geometry types. Use {@link ol.format.GeoJSON#readFeatures} to read
41918 * FeatureCollection source. If feature at source has an id, it will be used
41919 * as Feature id by calling {@link ol.Feature#setId} internally.
41920 *
41921 * @function
41922 * @param {Document|Node|Object|string} source Source.
41923 * @param {olx.format.ReadOptions=} opt_options Read options.
41924 * @return {ol.Feature} Feature.
41925 * @api
41926 */
41927ol.format.GeoJSON.prototype.readFeature;
41928
41929
41930/**
41931 * Read all features from a GeoJSON source. Works for all GeoJSON types.
41932 * If the source includes only geometries, features will be created with those
41933 * geometries.
41934 *
41935 * @function
41936 * @param {Document|Node|Object|string} source Source.
41937 * @param {olx.format.ReadOptions=} opt_options Read options.
41938 * @return {Array.<ol.Feature>} Features.
41939 * @api
41940 */
41941ol.format.GeoJSON.prototype.readFeatures;
41942
41943
41944/**
41945 * @inheritDoc
41946 */
41947ol.format.GeoJSON.prototype.readFeatureFromObject = function(
41948 object, opt_options) {
41949 /**
41950 * @type {GeoJSONFeature}
41951 */
41952 var geoJSONFeature = null;
41953 if (object.type === 'Feature') {
41954 geoJSONFeature = /** @type {GeoJSONFeature} */ (object);
41955 } else {
41956 geoJSONFeature = /** @type {GeoJSONFeature} */ ({
41957 type: 'Feature',
41958 geometry: /** @type {GeoJSONGeometry|GeoJSONGeometryCollection} */ (object)
41959 });
41960 }
41961
41962 var geometry = ol.format.GeoJSON.readGeometry_(geoJSONFeature.geometry, opt_options);
41963 var feature = new ol.Feature();
41964 if (this.geometryName_) {
41965 feature.setGeometryName(this.geometryName_);
41966 }
41967 feature.setGeometry(geometry);
41968 if (geoJSONFeature.id !== undefined) {
41969 feature.setId(geoJSONFeature.id);
41970 }
41971 if (geoJSONFeature.properties) {
41972 feature.setProperties(geoJSONFeature.properties);
41973 }
41974 return feature;
41975};
41976
41977
41978/**
41979 * @inheritDoc
41980 */
41981ol.format.GeoJSON.prototype.readFeaturesFromObject = function(
41982 object, opt_options) {
41983 var geoJSONObject = /** @type {GeoJSONObject} */ (object);
41984 /** @type {Array.<ol.Feature>} */
41985 var features = null;
41986 if (geoJSONObject.type === 'FeatureCollection') {
41987 var geoJSONFeatureCollection = /** @type {GeoJSONFeatureCollection} */
41988 (object);
41989 features = [];
41990 var geoJSONFeatures = geoJSONFeatureCollection.features;
41991 var i, ii;
41992 for (i = 0, ii = geoJSONFeatures.length; i < ii; ++i) {
41993 features.push(this.readFeatureFromObject(geoJSONFeatures[i],
41994 opt_options));
41995 }
41996 } else {
41997 features = [this.readFeatureFromObject(object, opt_options)];
41998 }
41999 return features;
42000};
42001
42002
42003/**
42004 * Read a geometry from a GeoJSON source.
42005 *
42006 * @function
42007 * @param {Document|Node|Object|string} source Source.
42008 * @param {olx.format.ReadOptions=} opt_options Read options.
42009 * @return {ol.geom.Geometry} Geometry.
42010 * @api
42011 */
42012ol.format.GeoJSON.prototype.readGeometry;
42013
42014
42015/**
42016 * @inheritDoc
42017 */
42018ol.format.GeoJSON.prototype.readGeometryFromObject = function(
42019 object, opt_options) {
42020 return ol.format.GeoJSON.readGeometry_(
42021 /** @type {GeoJSONGeometry} */ (object), opt_options);
42022};
42023
42024
42025/**
42026 * Read the projection from a GeoJSON source.
42027 *
42028 * @function
42029 * @param {Document|Node|Object|string} source Source.
42030 * @return {ol.proj.Projection} Projection.
42031 * @api
42032 */
42033ol.format.GeoJSON.prototype.readProjection;
42034
42035
42036/**
42037 * @inheritDoc
42038 */
42039ol.format.GeoJSON.prototype.readProjectionFromObject = function(object) {
42040 var geoJSONObject = /** @type {GeoJSONObject} */ (object);
42041 var crs = geoJSONObject.crs;
42042 var projection;
42043 if (crs) {
42044 if (crs.type == 'name') {
42045 projection = ol.proj.get(crs.properties.name);
42046 } else if (crs.type == 'EPSG') {
42047 // 'EPSG' is not part of the GeoJSON specification, but is generated by
42048 // GeoServer.
42049 // TODO: remove this when http://jira.codehaus.org/browse/GEOS-5996
42050 // is fixed and widely deployed.
42051 projection = ol.proj.get('EPSG:' + crs.properties.code);
42052 } else {
42053 ol.asserts.assert(false, 36); // Unknown SRS type
42054 }
42055 } else {
42056 projection = this.defaultDataProjection;
42057 }
42058 return /** @type {ol.proj.Projection} */ (projection);
42059};
42060
42061
42062/**
42063 * Encode a feature as a GeoJSON Feature string.
42064 *
42065 * @function
42066 * @param {ol.Feature} feature Feature.
42067 * @param {olx.format.WriteOptions=} opt_options Write options.
42068 * @return {string} GeoJSON.
42069 * @override
42070 * @api
42071 */
42072ol.format.GeoJSON.prototype.writeFeature;
42073
42074
42075/**
42076 * Encode a feature as a GeoJSON Feature object.
42077 *
42078 * @param {ol.Feature} feature Feature.
42079 * @param {olx.format.WriteOptions=} opt_options Write options.
42080 * @return {GeoJSONFeature} Object.
42081 * @override
42082 * @api
42083 */
42084ol.format.GeoJSON.prototype.writeFeatureObject = function(feature, opt_options) {
42085 opt_options = this.adaptOptions(opt_options);
42086
42087 var object = /** @type {GeoJSONFeature} */ ({
42088 'type': 'Feature'
42089 });
42090 var id = feature.getId();
42091 if (id !== undefined) {
42092 object.id = id;
42093 }
42094 var geometry = feature.getGeometry();
42095 if (geometry) {
42096 object.geometry =
42097 ol.format.GeoJSON.writeGeometry_(geometry, opt_options);
42098 } else {
42099 object.geometry = null;
42100 }
42101 var properties = feature.getProperties();
42102 delete properties[feature.getGeometryName()];
42103 if (!ol.obj.isEmpty(properties)) {
42104 object.properties = properties;
42105 } else {
42106 object.properties = null;
42107 }
42108 return object;
42109};
42110
42111
42112/**
42113 * Encode an array of features as GeoJSON.
42114 *
42115 * @function
42116 * @param {Array.<ol.Feature>} features Features.
42117 * @param {olx.format.WriteOptions=} opt_options Write options.
42118 * @return {string} GeoJSON.
42119 * @api
42120 */
42121ol.format.GeoJSON.prototype.writeFeatures;
42122
42123
42124/**
42125 * Encode an array of features as a GeoJSON object.
42126 *
42127 * @param {Array.<ol.Feature>} features Features.
42128 * @param {olx.format.WriteOptions=} opt_options Write options.
42129 * @return {GeoJSONFeatureCollection} GeoJSON Object.
42130 * @override
42131 * @api
42132 */
42133ol.format.GeoJSON.prototype.writeFeaturesObject = function(features, opt_options) {
42134 opt_options = this.adaptOptions(opt_options);
42135 var objects = [];
42136 var i, ii;
42137 for (i = 0, ii = features.length; i < ii; ++i) {
42138 objects.push(this.writeFeatureObject(features[i], opt_options));
42139 }
42140 return /** @type {GeoJSONFeatureCollection} */ ({
42141 type: 'FeatureCollection',
42142 features: objects
42143 });
42144};
42145
42146
42147/**
42148 * Encode a geometry as a GeoJSON string.
42149 *
42150 * @function
42151 * @param {ol.geom.Geometry} geometry Geometry.
42152 * @param {olx.format.WriteOptions=} opt_options Write options.
42153 * @return {string} GeoJSON.
42154 * @api
42155 */
42156ol.format.GeoJSON.prototype.writeGeometry;
42157
42158
42159/**
42160 * Encode a geometry as a GeoJSON object.
42161 *
42162 * @param {ol.geom.Geometry} geometry Geometry.
42163 * @param {olx.format.WriteOptions=} opt_options Write options.
42164 * @return {GeoJSONGeometry|GeoJSONGeometryCollection} Object.
42165 * @override
42166 * @api
42167 */
42168ol.format.GeoJSON.prototype.writeGeometryObject = function(geometry,
42169 opt_options) {
42170 return ol.format.GeoJSON.writeGeometry_(geometry,
42171 this.adaptOptions(opt_options));
42172};
42173
42174goog.provide('ol.format.XMLFeature');
42175
42176goog.require('ol');
42177goog.require('ol.array');
42178goog.require('ol.format.Feature');
42179goog.require('ol.format.FormatType');
42180goog.require('ol.xml');
42181
42182
42183/**
42184 * @classdesc
42185 * Abstract base class; normally only used for creating subclasses and not
42186 * instantiated in apps.
42187 * Base class for XML feature formats.
42188 *
42189 * @constructor
42190 * @abstract
42191 * @extends {ol.format.Feature}
42192 */
42193ol.format.XMLFeature = function() {
42194
42195 /**
42196 * @type {XMLSerializer}
42197 * @private
42198 */
42199 this.xmlSerializer_ = new XMLSerializer();
42200
42201 ol.format.Feature.call(this);
42202};
42203ol.inherits(ol.format.XMLFeature, ol.format.Feature);
42204
42205
42206/**
42207 * @inheritDoc
42208 */
42209ol.format.XMLFeature.prototype.getType = function() {
42210 return ol.format.FormatType.XML;
42211};
42212
42213
42214/**
42215 * @inheritDoc
42216 */
42217ol.format.XMLFeature.prototype.readFeature = function(source, opt_options) {
42218 if (ol.xml.isDocument(source)) {
42219 return this.readFeatureFromDocument(
42220 /** @type {Document} */ (source), opt_options);
42221 } else if (ol.xml.isNode(source)) {
42222 return this.readFeatureFromNode(/** @type {Node} */ (source), opt_options);
42223 } else if (typeof source === 'string') {
42224 var doc = ol.xml.parse(source);
42225 return this.readFeatureFromDocument(doc, opt_options);
42226 } else {
42227 return null;
42228 }
42229};
42230
42231
42232/**
42233 * @param {Document} doc Document.
42234 * @param {olx.format.ReadOptions=} opt_options Options.
42235 * @return {ol.Feature} Feature.
42236 */
42237ol.format.XMLFeature.prototype.readFeatureFromDocument = function(
42238 doc, opt_options) {
42239 var features = this.readFeaturesFromDocument(doc, opt_options);
42240 if (features.length > 0) {
42241 return features[0];
42242 } else {
42243 return null;
42244 }
42245};
42246
42247
42248/**
42249 * @param {Node} node Node.
42250 * @param {olx.format.ReadOptions=} opt_options Options.
42251 * @return {ol.Feature} Feature.
42252 */
42253ol.format.XMLFeature.prototype.readFeatureFromNode = function(node, opt_options) {
42254 return null; // not implemented
42255};
42256
42257
42258/**
42259 * @inheritDoc
42260 */
42261ol.format.XMLFeature.prototype.readFeatures = function(source, opt_options) {
42262 if (ol.xml.isDocument(source)) {
42263 return this.readFeaturesFromDocument(
42264 /** @type {Document} */ (source), opt_options);
42265 } else if (ol.xml.isNode(source)) {
42266 return this.readFeaturesFromNode(/** @type {Node} */ (source), opt_options);
42267 } else if (typeof source === 'string') {
42268 var doc = ol.xml.parse(source);
42269 return this.readFeaturesFromDocument(doc, opt_options);
42270 } else {
42271 return [];
42272 }
42273};
42274
42275
42276/**
42277 * @param {Document} doc Document.
42278 * @param {olx.format.ReadOptions=} opt_options Options.
42279 * @protected
42280 * @return {Array.<ol.Feature>} Features.
42281 */
42282ol.format.XMLFeature.prototype.readFeaturesFromDocument = function(
42283 doc, opt_options) {
42284 /** @type {Array.<ol.Feature>} */
42285 var features = [];
42286 var n;
42287 for (n = doc.firstChild; n; n = n.nextSibling) {
42288 if (n.nodeType == Node.ELEMENT_NODE) {
42289 ol.array.extend(features, this.readFeaturesFromNode(n, opt_options));
42290 }
42291 }
42292 return features;
42293};
42294
42295
42296/**
42297 * @abstract
42298 * @param {Node} node Node.
42299 * @param {olx.format.ReadOptions=} opt_options Options.
42300 * @protected
42301 * @return {Array.<ol.Feature>} Features.
42302 */
42303ol.format.XMLFeature.prototype.readFeaturesFromNode = function(node, opt_options) {};
42304
42305
42306/**
42307 * @inheritDoc
42308 */
42309ol.format.XMLFeature.prototype.readGeometry = function(source, opt_options) {
42310 if (ol.xml.isDocument(source)) {
42311 return this.readGeometryFromDocument(
42312 /** @type {Document} */ (source), opt_options);
42313 } else if (ol.xml.isNode(source)) {
42314 return this.readGeometryFromNode(/** @type {Node} */ (source), opt_options);
42315 } else if (typeof source === 'string') {
42316 var doc = ol.xml.parse(source);
42317 return this.readGeometryFromDocument(doc, opt_options);
42318 } else {
42319 return null;
42320 }
42321};
42322
42323
42324/**
42325 * @param {Document} doc Document.
42326 * @param {olx.format.ReadOptions=} opt_options Options.
42327 * @protected
42328 * @return {ol.geom.Geometry} Geometry.
42329 */
42330ol.format.XMLFeature.prototype.readGeometryFromDocument = function(doc, opt_options) {
42331 return null; // not implemented
42332};
42333
42334
42335/**
42336 * @param {Node} node Node.
42337 * @param {olx.format.ReadOptions=} opt_options Options.
42338 * @protected
42339 * @return {ol.geom.Geometry} Geometry.
42340 */
42341ol.format.XMLFeature.prototype.readGeometryFromNode = function(node, opt_options) {
42342 return null; // not implemented
42343};
42344
42345
42346/**
42347 * @inheritDoc
42348 */
42349ol.format.XMLFeature.prototype.readProjection = function(source) {
42350 if (ol.xml.isDocument(source)) {
42351 return this.readProjectionFromDocument(/** @type {Document} */ (source));
42352 } else if (ol.xml.isNode(source)) {
42353 return this.readProjectionFromNode(/** @type {Node} */ (source));
42354 } else if (typeof source === 'string') {
42355 var doc = ol.xml.parse(source);
42356 return this.readProjectionFromDocument(doc);
42357 } else {
42358 return null;
42359 }
42360};
42361
42362
42363/**
42364 * @param {Document} doc Document.
42365 * @protected
42366 * @return {ol.proj.Projection} Projection.
42367 */
42368ol.format.XMLFeature.prototype.readProjectionFromDocument = function(doc) {
42369 return this.defaultDataProjection;
42370};
42371
42372
42373/**
42374 * @param {Node} node Node.
42375 * @protected
42376 * @return {ol.proj.Projection} Projection.
42377 */
42378ol.format.XMLFeature.prototype.readProjectionFromNode = function(node) {
42379 return this.defaultDataProjection;
42380};
42381
42382
42383/**
42384 * @inheritDoc
42385 */
42386ol.format.XMLFeature.prototype.writeFeature = function(feature, opt_options) {
42387 var node = this.writeFeatureNode(feature, opt_options);
42388 return this.xmlSerializer_.serializeToString(node);
42389};
42390
42391
42392/**
42393 * @param {ol.Feature} feature Feature.
42394 * @param {olx.format.WriteOptions=} opt_options Options.
42395 * @protected
42396 * @return {Node} Node.
42397 */
42398ol.format.XMLFeature.prototype.writeFeatureNode = function(feature, opt_options) {
42399 return null; // not implemented
42400};
42401
42402
42403/**
42404 * @inheritDoc
42405 */
42406ol.format.XMLFeature.prototype.writeFeatures = function(features, opt_options) {
42407 var node = this.writeFeaturesNode(features, opt_options);
42408 return this.xmlSerializer_.serializeToString(node);
42409};
42410
42411
42412/**
42413 * @param {Array.<ol.Feature>} features Features.
42414 * @param {olx.format.WriteOptions=} opt_options Options.
42415 * @return {Node} Node.
42416 */
42417ol.format.XMLFeature.prototype.writeFeaturesNode = function(features, opt_options) {
42418 return null; // not implemented
42419};
42420
42421
42422/**
42423 * @inheritDoc
42424 */
42425ol.format.XMLFeature.prototype.writeGeometry = function(geometry, opt_options) {
42426 var node = this.writeGeometryNode(geometry, opt_options);
42427 return this.xmlSerializer_.serializeToString(node);
42428};
42429
42430
42431/**
42432 * @param {ol.geom.Geometry} geometry Geometry.
42433 * @param {olx.format.WriteOptions=} opt_options Options.
42434 * @return {Node} Node.
42435 */
42436ol.format.XMLFeature.prototype.writeGeometryNode = function(geometry, opt_options) {
42437 return null; // not implemented
42438};
42439
42440// FIXME Envelopes should not be treated as geometries! readEnvelope_ is part
42441// of GEOMETRY_PARSERS_ and methods using GEOMETRY_PARSERS_ do not expect
42442// envelopes/extents, only geometries!
42443goog.provide('ol.format.GMLBase');
42444
42445goog.require('ol');
42446goog.require('ol.array');
42447goog.require('ol.Feature');
42448goog.require('ol.format.Feature');
42449goog.require('ol.format.XMLFeature');
42450goog.require('ol.geom.GeometryLayout');
42451goog.require('ol.geom.LineString');
42452goog.require('ol.geom.LinearRing');
42453goog.require('ol.geom.MultiLineString');
42454goog.require('ol.geom.MultiPoint');
42455goog.require('ol.geom.MultiPolygon');
42456goog.require('ol.geom.Point');
42457goog.require('ol.geom.Polygon');
42458goog.require('ol.obj');
42459goog.require('ol.proj');
42460goog.require('ol.xml');
42461
42462
42463/**
42464 * @classdesc
42465 * Abstract base class; normally only used for creating subclasses and not
42466 * instantiated in apps.
42467 * Feature base format for reading and writing data in the GML format.
42468 * This class cannot be instantiated, it contains only base content that
42469 * is shared with versioned format classes ol.format.GML2 and
42470 * ol.format.GML3.
42471 *
42472 * @constructor
42473 * @abstract
42474 * @param {olx.format.GMLOptions=} opt_options
42475 * Optional configuration object.
42476 * @extends {ol.format.XMLFeature}
42477 */
42478ol.format.GMLBase = function(opt_options) {
42479 var options = /** @type {olx.format.GMLOptions} */
42480 (opt_options ? opt_options : {});
42481
42482 /**
42483 * @protected
42484 * @type {Array.<string>|string|undefined}
42485 */
42486 this.featureType = options.featureType;
42487
42488 /**
42489 * @protected
42490 * @type {Object.<string, string>|string|undefined}
42491 */
42492 this.featureNS = options.featureNS;
42493
42494 /**
42495 * @protected
42496 * @type {string}
42497 */
42498 this.srsName = options.srsName;
42499
42500 /**
42501 * @protected
42502 * @type {string}
42503 */
42504 this.schemaLocation = '';
42505
42506 /**
42507 * @type {Object.<string, Object.<string, Object>>}
42508 */
42509 this.FEATURE_COLLECTION_PARSERS = {};
42510 this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS] = {
42511 'featureMember': ol.xml.makeReplacer(
42512 ol.format.GMLBase.prototype.readFeaturesInternal),
42513 'featureMembers': ol.xml.makeReplacer(
42514 ol.format.GMLBase.prototype.readFeaturesInternal)
42515 };
42516
42517 ol.format.XMLFeature.call(this);
42518};
42519ol.inherits(ol.format.GMLBase, ol.format.XMLFeature);
42520
42521
42522/**
42523 * @const
42524 * @type {string}
42525 */
42526ol.format.GMLBase.GMLNS = 'http://www.opengis.net/gml';
42527
42528
42529/**
42530 * A regular expression that matches if a string only contains whitespace
42531 * characters. It will e.g. match `''`, `' '`, `'\n'` etc. The non-breaking
42532 * space (0xa0) is explicitly included as IE doesn't include it in its
42533 * definition of `\s`.
42534 *
42535 * Information from `goog.string.isEmptyOrWhitespace`: https://github.com/google/closure-library/blob/e877b1e/closure/goog/string/string.js#L156-L160
42536 *
42537 * @const
42538 * @type {RegExp}
42539 * @private
42540 */
42541ol.format.GMLBase.ONLY_WHITESPACE_RE_ = /^[\s\xa0]*$/;
42542
42543
42544/**
42545 * @param {Node} node Node.
42546 * @param {Array.<*>} objectStack Object stack.
42547 * @return {Array.<ol.Feature> | undefined} Features.
42548 */
42549ol.format.GMLBase.prototype.readFeaturesInternal = function(node, objectStack) {
42550 var localName = node.localName;
42551 var features = null;
42552 if (localName == 'FeatureCollection') {
42553 if (node.namespaceURI === 'http://www.opengis.net/wfs') {
42554 features = ol.xml.pushParseAndPop([],
42555 this.FEATURE_COLLECTION_PARSERS, node,
42556 objectStack, this);
42557 } else {
42558 features = ol.xml.pushParseAndPop(null,
42559 this.FEATURE_COLLECTION_PARSERS, node,
42560 objectStack, this);
42561 }
42562 } else if (localName == 'featureMembers' || localName == 'featureMember') {
42563 var context = objectStack[0];
42564 var featureType = context['featureType'];
42565 var featureNS = context['featureNS'];
42566 var i, ii, prefix = 'p', defaultPrefix = 'p0';
42567 if (!featureType && node.childNodes) {
42568 featureType = [], featureNS = {};
42569 for (i = 0, ii = node.childNodes.length; i < ii; ++i) {
42570 var child = node.childNodes[i];
42571 if (child.nodeType === 1) {
42572 var ft = child.nodeName.split(':').pop();
42573 if (featureType.indexOf(ft) === -1) {
42574 var key = '';
42575 var count = 0;
42576 var uri = child.namespaceURI;
42577 for (var candidate in featureNS) {
42578 if (featureNS[candidate] === uri) {
42579 key = candidate;
42580 break;
42581 }
42582 ++count;
42583 }
42584 if (!key) {
42585 key = prefix + count;
42586 featureNS[key] = uri;
42587 }
42588 featureType.push(key + ':' + ft);
42589 }
42590 }
42591 }
42592 if (localName != 'featureMember') {
42593 // recheck featureType for each featureMember
42594 context['featureType'] = featureType;
42595 context['featureNS'] = featureNS;
42596 }
42597 }
42598 if (typeof featureNS === 'string') {
42599 var ns = featureNS;
42600 featureNS = {};
42601 featureNS[defaultPrefix] = ns;
42602 }
42603 var parsersNS = {};
42604 var featureTypes = Array.isArray(featureType) ? featureType : [featureType];
42605 for (var p in featureNS) {
42606 var parsers = {};
42607 for (i = 0, ii = featureTypes.length; i < ii; ++i) {
42608 var featurePrefix = featureTypes[i].indexOf(':') === -1 ?
42609 defaultPrefix : featureTypes[i].split(':')[0];
42610 if (featurePrefix === p) {
42611 parsers[featureTypes[i].split(':').pop()] =
42612 (localName == 'featureMembers') ?
42613 ol.xml.makeArrayPusher(this.readFeatureElement, this) :
42614 ol.xml.makeReplacer(this.readFeatureElement, this);
42615 }
42616 }
42617 parsersNS[featureNS[p]] = parsers;
42618 }
42619 if (localName == 'featureMember') {
42620 features = ol.xml.pushParseAndPop(undefined, parsersNS, node, objectStack);
42621 } else {
42622 features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack);
42623 }
42624 }
42625 if (features === null) {
42626 features = [];
42627 }
42628 return features;
42629};
42630
42631
42632/**
42633 * @param {Node} node Node.
42634 * @param {Array.<*>} objectStack Object stack.
42635 * @return {ol.geom.Geometry|undefined} Geometry.
42636 */
42637ol.format.GMLBase.prototype.readGeometryElement = function(node, objectStack) {
42638 var context = /** @type {Object} */ (objectStack[0]);
42639 context['srsName'] = node.firstElementChild.getAttribute('srsName');
42640 /** @type {ol.geom.Geometry} */
42641 var geometry = ol.xml.pushParseAndPop(null,
42642 this.GEOMETRY_PARSERS_, node, objectStack, this);
42643 if (geometry) {
42644 return /** @type {ol.geom.Geometry} */ (
42645 ol.format.Feature.transformWithOptions(geometry, false, context));
42646 } else {
42647 return undefined;
42648 }
42649};
42650
42651
42652/**
42653 * @param {Node} node Node.
42654 * @param {Array.<*>} objectStack Object stack.
42655 * @return {ol.Feature} Feature.
42656 */
42657ol.format.GMLBase.prototype.readFeatureElement = function(node, objectStack) {
42658 var n;
42659 var fid = node.getAttribute('fid') ||
42660 ol.xml.getAttributeNS(node, ol.format.GMLBase.GMLNS, 'id');
42661 var values = {}, geometryName;
42662 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
42663 var localName = n.localName;
42664 // Assume attribute elements have one child node and that the child
42665 // is a text or CDATA node (to be treated as text).
42666 // Otherwise assume it is a geometry node.
42667 if (n.childNodes.length === 0 ||
42668 (n.childNodes.length === 1 &&
42669 (n.firstChild.nodeType === 3 || n.firstChild.nodeType === 4))) {
42670 var value = ol.xml.getAllTextContent(n, false);
42671 if (ol.format.GMLBase.ONLY_WHITESPACE_RE_.test(value)) {
42672 value = undefined;
42673 }
42674 values[localName] = value;
42675 } else {
42676 // boundedBy is an extent and must not be considered as a geometry
42677 if (localName !== 'boundedBy') {
42678 geometryName = localName;
42679 }
42680 values[localName] = this.readGeometryElement(n, objectStack);
42681 }
42682 }
42683 var feature = new ol.Feature(values);
42684 if (geometryName) {
42685 feature.setGeometryName(geometryName);
42686 }
42687 if (fid) {
42688 feature.setId(fid);
42689 }
42690 return feature;
42691};
42692
42693
42694/**
42695 * @param {Node} node Node.
42696 * @param {Array.<*>} objectStack Object stack.
42697 * @return {ol.geom.Point|undefined} Point.
42698 */
42699ol.format.GMLBase.prototype.readPoint = function(node, objectStack) {
42700 var flatCoordinates =
42701 this.readFlatCoordinatesFromNode_(node, objectStack);
42702 if (flatCoordinates) {
42703 var point = new ol.geom.Point(null);
42704 point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
42705 return point;
42706 }
42707};
42708
42709
42710/**
42711 * @param {Node} node Node.
42712 * @param {Array.<*>} objectStack Object stack.
42713 * @return {ol.geom.MultiPoint|undefined} MultiPoint.
42714 */
42715ol.format.GMLBase.prototype.readMultiPoint = function(node, objectStack) {
42716 /** @type {Array.<Array.<number>>} */
42717 var coordinates = ol.xml.pushParseAndPop([],
42718 this.MULTIPOINT_PARSERS_, node, objectStack, this);
42719 if (coordinates) {
42720 return new ol.geom.MultiPoint(coordinates);
42721 } else {
42722 return undefined;
42723 }
42724};
42725
42726
42727/**
42728 * @param {Node} node Node.
42729 * @param {Array.<*>} objectStack Object stack.
42730 * @return {ol.geom.MultiLineString|undefined} MultiLineString.
42731 */
42732ol.format.GMLBase.prototype.readMultiLineString = function(node, objectStack) {
42733 /** @type {Array.<ol.geom.LineString>} */
42734 var lineStrings = ol.xml.pushParseAndPop([],
42735 this.MULTILINESTRING_PARSERS_, node, objectStack, this);
42736 if (lineStrings) {
42737 var multiLineString = new ol.geom.MultiLineString(null);
42738 multiLineString.setLineStrings(lineStrings);
42739 return multiLineString;
42740 } else {
42741 return undefined;
42742 }
42743};
42744
42745
42746/**
42747 * @param {Node} node Node.
42748 * @param {Array.<*>} objectStack Object stack.
42749 * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.
42750 */
42751ol.format.GMLBase.prototype.readMultiPolygon = function(node, objectStack) {
42752 /** @type {Array.<ol.geom.Polygon>} */
42753 var polygons = ol.xml.pushParseAndPop([],
42754 this.MULTIPOLYGON_PARSERS_, node, objectStack, this);
42755 if (polygons) {
42756 var multiPolygon = new ol.geom.MultiPolygon(null);
42757 multiPolygon.setPolygons(polygons);
42758 return multiPolygon;
42759 } else {
42760 return undefined;
42761 }
42762};
42763
42764
42765/**
42766 * @param {Node} node Node.
42767 * @param {Array.<*>} objectStack Object stack.
42768 * @private
42769 */
42770ol.format.GMLBase.prototype.pointMemberParser_ = function(node, objectStack) {
42771 ol.xml.parseNode(this.POINTMEMBER_PARSERS_,
42772 node, objectStack, this);
42773};
42774
42775
42776/**
42777 * @param {Node} node Node.
42778 * @param {Array.<*>} objectStack Object stack.
42779 * @private
42780 */
42781ol.format.GMLBase.prototype.lineStringMemberParser_ = function(node, objectStack) {
42782 ol.xml.parseNode(this.LINESTRINGMEMBER_PARSERS_,
42783 node, objectStack, this);
42784};
42785
42786
42787/**
42788 * @param {Node} node Node.
42789 * @param {Array.<*>} objectStack Object stack.
42790 * @private
42791 */
42792ol.format.GMLBase.prototype.polygonMemberParser_ = function(node, objectStack) {
42793 ol.xml.parseNode(this.POLYGONMEMBER_PARSERS_, node,
42794 objectStack, this);
42795};
42796
42797
42798/**
42799 * @param {Node} node Node.
42800 * @param {Array.<*>} objectStack Object stack.
42801 * @return {ol.geom.LineString|undefined} LineString.
42802 */
42803ol.format.GMLBase.prototype.readLineString = function(node, objectStack) {
42804 var flatCoordinates =
42805 this.readFlatCoordinatesFromNode_(node, objectStack);
42806 if (flatCoordinates) {
42807 var lineString = new ol.geom.LineString(null);
42808 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
42809 return lineString;
42810 } else {
42811 return undefined;
42812 }
42813};
42814
42815
42816/**
42817 * @param {Node} node Node.
42818 * @param {Array.<*>} objectStack Object stack.
42819 * @private
42820 * @return {Array.<number>|undefined} LinearRing flat coordinates.
42821 */
42822ol.format.GMLBase.prototype.readFlatLinearRing_ = function(node, objectStack) {
42823 var ring = ol.xml.pushParseAndPop(null,
42824 this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
42825 objectStack, this);
42826 if (ring) {
42827 return ring;
42828 } else {
42829 return undefined;
42830 }
42831};
42832
42833
42834/**
42835 * @param {Node} node Node.
42836 * @param {Array.<*>} objectStack Object stack.
42837 * @return {ol.geom.LinearRing|undefined} LinearRing.
42838 */
42839ol.format.GMLBase.prototype.readLinearRing = function(node, objectStack) {
42840 var flatCoordinates =
42841 this.readFlatCoordinatesFromNode_(node, objectStack);
42842 if (flatCoordinates) {
42843 var ring = new ol.geom.LinearRing(null);
42844 ring.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
42845 return ring;
42846 } else {
42847 return undefined;
42848 }
42849};
42850
42851
42852/**
42853 * @param {Node} node Node.
42854 * @param {Array.<*>} objectStack Object stack.
42855 * @return {ol.geom.Polygon|undefined} Polygon.
42856 */
42857ol.format.GMLBase.prototype.readPolygon = function(node, objectStack) {
42858 /** @type {Array.<Array.<number>>} */
42859 var flatLinearRings = ol.xml.pushParseAndPop([null],
42860 this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
42861 if (flatLinearRings && flatLinearRings[0]) {
42862 var polygon = new ol.geom.Polygon(null);
42863 var flatCoordinates = flatLinearRings[0];
42864 var ends = [flatCoordinates.length];
42865 var i, ii;
42866 for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
42867 ol.array.extend(flatCoordinates, flatLinearRings[i]);
42868 ends.push(flatCoordinates.length);
42869 }
42870 polygon.setFlatCoordinates(
42871 ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
42872 return polygon;
42873 } else {
42874 return undefined;
42875 }
42876};
42877
42878
42879/**
42880 * @param {Node} node Node.
42881 * @param {Array.<*>} objectStack Object stack.
42882 * @private
42883 * @return {Array.<number>} Flat coordinates.
42884 */
42885ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_ = function(node, objectStack) {
42886 return ol.xml.pushParseAndPop(null,
42887 this.GEOMETRY_FLAT_COORDINATES_PARSERS_, node,
42888 objectStack, this);
42889};
42890
42891
42892/**
42893 * @const
42894 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42895 * @private
42896 */
42897ol.format.GMLBase.prototype.MULTIPOINT_PARSERS_ = {
42898 'http://www.opengis.net/gml': {
42899 'pointMember': ol.xml.makeArrayPusher(
42900 ol.format.GMLBase.prototype.pointMemberParser_),
42901 'pointMembers': ol.xml.makeArrayPusher(
42902 ol.format.GMLBase.prototype.pointMemberParser_)
42903 }
42904};
42905
42906
42907/**
42908 * @const
42909 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42910 * @private
42911 */
42912ol.format.GMLBase.prototype.MULTILINESTRING_PARSERS_ = {
42913 'http://www.opengis.net/gml': {
42914 'lineStringMember': ol.xml.makeArrayPusher(
42915 ol.format.GMLBase.prototype.lineStringMemberParser_),
42916 'lineStringMembers': ol.xml.makeArrayPusher(
42917 ol.format.GMLBase.prototype.lineStringMemberParser_)
42918 }
42919};
42920
42921
42922/**
42923 * @const
42924 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42925 * @private
42926 */
42927ol.format.GMLBase.prototype.MULTIPOLYGON_PARSERS_ = {
42928 'http://www.opengis.net/gml': {
42929 'polygonMember': ol.xml.makeArrayPusher(
42930 ol.format.GMLBase.prototype.polygonMemberParser_),
42931 'polygonMembers': ol.xml.makeArrayPusher(
42932 ol.format.GMLBase.prototype.polygonMemberParser_)
42933 }
42934};
42935
42936
42937/**
42938 * @const
42939 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42940 * @private
42941 */
42942ol.format.GMLBase.prototype.POINTMEMBER_PARSERS_ = {
42943 'http://www.opengis.net/gml': {
42944 'Point': ol.xml.makeArrayPusher(
42945 ol.format.GMLBase.prototype.readFlatCoordinatesFromNode_)
42946 }
42947};
42948
42949
42950/**
42951 * @const
42952 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42953 * @private
42954 */
42955ol.format.GMLBase.prototype.LINESTRINGMEMBER_PARSERS_ = {
42956 'http://www.opengis.net/gml': {
42957 'LineString': ol.xml.makeArrayPusher(
42958 ol.format.GMLBase.prototype.readLineString)
42959 }
42960};
42961
42962
42963/**
42964 * @const
42965 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42966 * @private
42967 */
42968ol.format.GMLBase.prototype.POLYGONMEMBER_PARSERS_ = {
42969 'http://www.opengis.net/gml': {
42970 'Polygon': ol.xml.makeArrayPusher(
42971 ol.format.GMLBase.prototype.readPolygon)
42972 }
42973};
42974
42975
42976/**
42977 * @const
42978 * @type {Object.<string, Object.<string, ol.XmlParser>>}
42979 * @protected
42980 */
42981ol.format.GMLBase.prototype.RING_PARSERS = {
42982 'http://www.opengis.net/gml': {
42983 'LinearRing': ol.xml.makeReplacer(
42984 ol.format.GMLBase.prototype.readFlatLinearRing_)
42985 }
42986};
42987
42988
42989/**
42990 * @inheritDoc
42991 */
42992ol.format.GMLBase.prototype.readGeometryFromNode = function(node, opt_options) {
42993 var geometry = this.readGeometryElement(node,
42994 [this.getReadOptions(node, opt_options ? opt_options : {})]);
42995 return geometry ? geometry : null;
42996};
42997
42998
42999/**
43000 * Read all features from a GML FeatureCollection.
43001 *
43002 * @function
43003 * @param {Document|Node|Object|string} source Source.
43004 * @param {olx.format.ReadOptions=} opt_options Options.
43005 * @return {Array.<ol.Feature>} Features.
43006 * @api
43007 */
43008ol.format.GMLBase.prototype.readFeatures;
43009
43010
43011/**
43012 * @inheritDoc
43013 */
43014ol.format.GMLBase.prototype.readFeaturesFromNode = function(node, opt_options) {
43015 var options = {
43016 featureType: this.featureType,
43017 featureNS: this.featureNS
43018 };
43019 if (opt_options) {
43020 ol.obj.assign(options, this.getReadOptions(node, opt_options));
43021 }
43022 var features = this.readFeaturesInternal(node, [options]);
43023 return features || [];
43024};
43025
43026
43027/**
43028 * @inheritDoc
43029 */
43030ol.format.GMLBase.prototype.readProjectionFromNode = function(node) {
43031 return ol.proj.get(this.srsName ? this.srsName :
43032 node.firstElementChild.getAttribute('srsName'));
43033};
43034
43035goog.provide('ol.format.XSD');
43036
43037goog.require('ol.xml');
43038goog.require('ol.string');
43039
43040
43041/**
43042 * @const
43043 * @type {string}
43044 */
43045ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema';
43046
43047
43048/**
43049 * @param {Node} node Node.
43050 * @return {boolean|undefined} Boolean.
43051 */
43052ol.format.XSD.readBoolean = function(node) {
43053 var s = ol.xml.getAllTextContent(node, false);
43054 return ol.format.XSD.readBooleanString(s);
43055};
43056
43057
43058/**
43059 * @param {string} string String.
43060 * @return {boolean|undefined} Boolean.
43061 */
43062ol.format.XSD.readBooleanString = function(string) {
43063 var m = /^\s*(true|1)|(false|0)\s*$/.exec(string);
43064 if (m) {
43065 return m[1] !== undefined || false;
43066 } else {
43067 return undefined;
43068 }
43069};
43070
43071
43072/**
43073 * @param {Node} node Node.
43074 * @return {number|undefined} DateTime in seconds.
43075 */
43076ol.format.XSD.readDateTime = function(node) {
43077 var s = ol.xml.getAllTextContent(node, false);
43078 var dateTime = Date.parse(s);
43079 return isNaN(dateTime) ? undefined : dateTime / 1000;
43080};
43081
43082
43083/**
43084 * @param {Node} node Node.
43085 * @return {number|undefined} Decimal.
43086 */
43087ol.format.XSD.readDecimal = function(node) {
43088 var s = ol.xml.getAllTextContent(node, false);
43089 return ol.format.XSD.readDecimalString(s);
43090};
43091
43092
43093/**
43094 * @param {string} string String.
43095 * @return {number|undefined} Decimal.
43096 */
43097ol.format.XSD.readDecimalString = function(string) {
43098 // FIXME check spec
43099 var m = /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(string);
43100 if (m) {
43101 return parseFloat(m[1]);
43102 } else {
43103 return undefined;
43104 }
43105};
43106
43107
43108/**
43109 * @param {Node} node Node.
43110 * @return {number|undefined} Non negative integer.
43111 */
43112ol.format.XSD.readNonNegativeInteger = function(node) {
43113 var s = ol.xml.getAllTextContent(node, false);
43114 return ol.format.XSD.readNonNegativeIntegerString(s);
43115};
43116
43117
43118/**
43119 * @param {string} string String.
43120 * @return {number|undefined} Non negative integer.
43121 */
43122ol.format.XSD.readNonNegativeIntegerString = function(string) {
43123 var m = /^\s*(\d+)\s*$/.exec(string);
43124 if (m) {
43125 return parseInt(m[1], 10);
43126 } else {
43127 return undefined;
43128 }
43129};
43130
43131
43132/**
43133 * @param {Node} node Node.
43134 * @return {string|undefined} String.
43135 */
43136ol.format.XSD.readString = function(node) {
43137 return ol.xml.getAllTextContent(node, false).trim();
43138};
43139
43140
43141/**
43142 * @param {Node} node Node to append a TextNode with the boolean to.
43143 * @param {boolean} bool Boolean.
43144 */
43145ol.format.XSD.writeBooleanTextNode = function(node, bool) {
43146 ol.format.XSD.writeStringTextNode(node, (bool) ? '1' : '0');
43147};
43148
43149
43150/**
43151 * @param {Node} node Node to append a CDATA Section with the string to.
43152 * @param {string} string String.
43153 */
43154ol.format.XSD.writeCDATASection = function(node, string) {
43155 node.appendChild(ol.xml.DOCUMENT.createCDATASection(string));
43156};
43157
43158
43159/**
43160 * @param {Node} node Node to append a TextNode with the dateTime to.
43161 * @param {number} dateTime DateTime in seconds.
43162 */
43163ol.format.XSD.writeDateTimeTextNode = function(node, dateTime) {
43164 var date = new Date(dateTime * 1000);
43165 var string = date.getUTCFullYear() + '-' +
43166 ol.string.padNumber(date.getUTCMonth() + 1, 2) + '-' +
43167 ol.string.padNumber(date.getUTCDate(), 2) + 'T' +
43168 ol.string.padNumber(date.getUTCHours(), 2) + ':' +
43169 ol.string.padNumber(date.getUTCMinutes(), 2) + ':' +
43170 ol.string.padNumber(date.getUTCSeconds(), 2) + 'Z';
43171 node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
43172};
43173
43174
43175/**
43176 * @param {Node} node Node to append a TextNode with the decimal to.
43177 * @param {number} decimal Decimal.
43178 */
43179ol.format.XSD.writeDecimalTextNode = function(node, decimal) {
43180 var string = decimal.toPrecision();
43181 node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
43182};
43183
43184
43185/**
43186 * @param {Node} node Node to append a TextNode with the decimal to.
43187 * @param {number} nonNegativeInteger Non negative integer.
43188 */
43189ol.format.XSD.writeNonNegativeIntegerTextNode = function(node, nonNegativeInteger) {
43190 var string = nonNegativeInteger.toString();
43191 node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
43192};
43193
43194
43195/**
43196 * @param {Node} node Node to append a TextNode with the string to.
43197 * @param {string} string String.
43198 */
43199ol.format.XSD.writeStringTextNode = function(node, string) {
43200 node.appendChild(ol.xml.DOCUMENT.createTextNode(string));
43201};
43202
43203goog.provide('ol.format.GML3');
43204
43205goog.require('ol');
43206goog.require('ol.array');
43207goog.require('ol.extent');
43208goog.require('ol.format.Feature');
43209goog.require('ol.format.GMLBase');
43210goog.require('ol.format.XSD');
43211goog.require('ol.geom.Geometry');
43212goog.require('ol.geom.GeometryLayout');
43213goog.require('ol.geom.LineString');
43214goog.require('ol.geom.MultiLineString');
43215goog.require('ol.geom.MultiPolygon');
43216goog.require('ol.geom.Polygon');
43217goog.require('ol.obj');
43218goog.require('ol.proj');
43219goog.require('ol.xml');
43220
43221
43222/**
43223 * @classdesc
43224 * Feature format for reading and writing data in the GML format
43225 * version 3.1.1.
43226 * Currently only supports GML 3.1.1 Simple Features profile.
43227 *
43228 * @constructor
43229 * @param {olx.format.GMLOptions=} opt_options
43230 * Optional configuration object.
43231 * @extends {ol.format.GMLBase}
43232 * @api
43233 */
43234ol.format.GML3 = function(opt_options) {
43235 var options = /** @type {olx.format.GMLOptions} */
43236 (opt_options ? opt_options : {});
43237
43238 ol.format.GMLBase.call(this, options);
43239
43240 /**
43241 * @private
43242 * @type {boolean}
43243 */
43244 this.surface_ = options.surface !== undefined ? options.surface : false;
43245
43246 /**
43247 * @private
43248 * @type {boolean}
43249 */
43250 this.curve_ = options.curve !== undefined ? options.curve : false;
43251
43252 /**
43253 * @private
43254 * @type {boolean}
43255 */
43256 this.multiCurve_ = options.multiCurve !== undefined ?
43257 options.multiCurve : true;
43258
43259 /**
43260 * @private
43261 * @type {boolean}
43262 */
43263 this.multiSurface_ = options.multiSurface !== undefined ?
43264 options.multiSurface : true;
43265
43266 /**
43267 * @inheritDoc
43268 */
43269 this.schemaLocation = options.schemaLocation ?
43270 options.schemaLocation : ol.format.GML3.schemaLocation_;
43271
43272 /**
43273 * @private
43274 * @type {boolean}
43275 */
43276 this.hasZ = options.hasZ !== undefined ?
43277 options.hasZ : false;
43278
43279};
43280ol.inherits(ol.format.GML3, ol.format.GMLBase);
43281
43282
43283/**
43284 * @const
43285 * @type {string}
43286 * @private
43287 */
43288ol.format.GML3.schemaLocation_ = ol.format.GMLBase.GMLNS +
43289 ' http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/' +
43290 '1.0.0/gmlsf.xsd';
43291
43292
43293/**
43294 * @param {Node} node Node.
43295 * @param {Array.<*>} objectStack Object stack.
43296 * @private
43297 * @return {ol.geom.MultiLineString|undefined} MultiLineString.
43298 */
43299ol.format.GML3.prototype.readMultiCurve_ = function(node, objectStack) {
43300 /** @type {Array.<ol.geom.LineString>} */
43301 var lineStrings = ol.xml.pushParseAndPop([],
43302 this.MULTICURVE_PARSERS_, node, objectStack, this);
43303 if (lineStrings) {
43304 var multiLineString = new ol.geom.MultiLineString(null);
43305 multiLineString.setLineStrings(lineStrings);
43306 return multiLineString;
43307 } else {
43308 return undefined;
43309 }
43310};
43311
43312
43313/**
43314 * @param {Node} node Node.
43315 * @param {Array.<*>} objectStack Object stack.
43316 * @private
43317 * @return {ol.geom.MultiPolygon|undefined} MultiPolygon.
43318 */
43319ol.format.GML3.prototype.readMultiSurface_ = function(node, objectStack) {
43320 /** @type {Array.<ol.geom.Polygon>} */
43321 var polygons = ol.xml.pushParseAndPop([],
43322 this.MULTISURFACE_PARSERS_, node, objectStack, this);
43323 if (polygons) {
43324 var multiPolygon = new ol.geom.MultiPolygon(null);
43325 multiPolygon.setPolygons(polygons);
43326 return multiPolygon;
43327 } else {
43328 return undefined;
43329 }
43330};
43331
43332
43333/**
43334 * @param {Node} node Node.
43335 * @param {Array.<*>} objectStack Object stack.
43336 * @private
43337 */
43338ol.format.GML3.prototype.curveMemberParser_ = function(node, objectStack) {
43339 ol.xml.parseNode(this.CURVEMEMBER_PARSERS_, node, objectStack, this);
43340};
43341
43342
43343/**
43344 * @param {Node} node Node.
43345 * @param {Array.<*>} objectStack Object stack.
43346 * @private
43347 */
43348ol.format.GML3.prototype.surfaceMemberParser_ = function(node, objectStack) {
43349 ol.xml.parseNode(this.SURFACEMEMBER_PARSERS_,
43350 node, objectStack, this);
43351};
43352
43353
43354/**
43355 * @param {Node} node Node.
43356 * @param {Array.<*>} objectStack Object stack.
43357 * @private
43358 * @return {Array.<(Array.<number>)>|undefined} flat coordinates.
43359 */
43360ol.format.GML3.prototype.readPatch_ = function(node, objectStack) {
43361 return ol.xml.pushParseAndPop([null],
43362 this.PATCHES_PARSERS_, node, objectStack, this);
43363};
43364
43365
43366/**
43367 * @param {Node} node Node.
43368 * @param {Array.<*>} objectStack Object stack.
43369 * @private
43370 * @return {Array.<number>|undefined} flat coordinates.
43371 */
43372ol.format.GML3.prototype.readSegment_ = function(node, objectStack) {
43373 return ol.xml.pushParseAndPop([null],
43374 this.SEGMENTS_PARSERS_, node, objectStack, this);
43375};
43376
43377
43378/**
43379 * @param {Node} node Node.
43380 * @param {Array.<*>} objectStack Object stack.
43381 * @private
43382 * @return {Array.<(Array.<number>)>|undefined} flat coordinates.
43383 */
43384ol.format.GML3.prototype.readPolygonPatch_ = function(node, objectStack) {
43385 return ol.xml.pushParseAndPop([null],
43386 this.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack, this);
43387};
43388
43389
43390/**
43391 * @param {Node} node Node.
43392 * @param {Array.<*>} objectStack Object stack.
43393 * @private
43394 * @return {Array.<number>|undefined} flat coordinates.
43395 */
43396ol.format.GML3.prototype.readLineStringSegment_ = function(node, objectStack) {
43397 return ol.xml.pushParseAndPop([null],
43398 this.GEOMETRY_FLAT_COORDINATES_PARSERS_,
43399 node, objectStack, this);
43400};
43401
43402
43403/**
43404 * @param {Node} node Node.
43405 * @param {Array.<*>} objectStack Object stack.
43406 * @private
43407 */
43408ol.format.GML3.prototype.interiorParser_ = function(node, objectStack) {
43409 /** @type {Array.<number>|undefined} */
43410 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
43411 this.RING_PARSERS, node, objectStack, this);
43412 if (flatLinearRing) {
43413 var flatLinearRings = /** @type {Array.<Array.<number>>} */
43414 (objectStack[objectStack.length - 1]);
43415 flatLinearRings.push(flatLinearRing);
43416 }
43417};
43418
43419
43420/**
43421 * @param {Node} node Node.
43422 * @param {Array.<*>} objectStack Object stack.
43423 * @private
43424 */
43425ol.format.GML3.prototype.exteriorParser_ = function(node, objectStack) {
43426 /** @type {Array.<number>|undefined} */
43427 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
43428 this.RING_PARSERS, node, objectStack, this);
43429 if (flatLinearRing) {
43430 var flatLinearRings = /** @type {Array.<Array.<number>>} */
43431 (objectStack[objectStack.length - 1]);
43432 flatLinearRings[0] = flatLinearRing;
43433 }
43434};
43435
43436
43437/**
43438 * @param {Node} node Node.
43439 * @param {Array.<*>} objectStack Object stack.
43440 * @private
43441 * @return {ol.geom.Polygon|undefined} Polygon.
43442 */
43443ol.format.GML3.prototype.readSurface_ = function(node, objectStack) {
43444 /** @type {Array.<Array.<number>>} */
43445 var flatLinearRings = ol.xml.pushParseAndPop([null],
43446 this.SURFACE_PARSERS_, node, objectStack, this);
43447 if (flatLinearRings && flatLinearRings[0]) {
43448 var polygon = new ol.geom.Polygon(null);
43449 var flatCoordinates = flatLinearRings[0];
43450 var ends = [flatCoordinates.length];
43451 var i, ii;
43452 for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
43453 ol.array.extend(flatCoordinates, flatLinearRings[i]);
43454 ends.push(flatCoordinates.length);
43455 }
43456 polygon.setFlatCoordinates(
43457 ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
43458 return polygon;
43459 } else {
43460 return undefined;
43461 }
43462};
43463
43464
43465/**
43466 * @param {Node} node Node.
43467 * @param {Array.<*>} objectStack Object stack.
43468 * @private
43469 * @return {ol.geom.LineString|undefined} LineString.
43470 */
43471ol.format.GML3.prototype.readCurve_ = function(node, objectStack) {
43472 /** @type {Array.<number>} */
43473 var flatCoordinates = ol.xml.pushParseAndPop([null],
43474 this.CURVE_PARSERS_, node, objectStack, this);
43475 if (flatCoordinates) {
43476 var lineString = new ol.geom.LineString(null);
43477 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
43478 return lineString;
43479 } else {
43480 return undefined;
43481 }
43482};
43483
43484
43485/**
43486 * @param {Node} node Node.
43487 * @param {Array.<*>} objectStack Object stack.
43488 * @private
43489 * @return {ol.Extent|undefined} Envelope.
43490 */
43491ol.format.GML3.prototype.readEnvelope_ = function(node, objectStack) {
43492 /** @type {Array.<number>} */
43493 var flatCoordinates = ol.xml.pushParseAndPop([null],
43494 this.ENVELOPE_PARSERS_, node, objectStack, this);
43495 return ol.extent.createOrUpdate(flatCoordinates[1][0],
43496 flatCoordinates[1][1], flatCoordinates[2][0],
43497 flatCoordinates[2][1]);
43498};
43499
43500
43501/**
43502 * @param {Node} node Node.
43503 * @param {Array.<*>} objectStack Object stack.
43504 * @private
43505 * @return {Array.<number>|undefined} Flat coordinates.
43506 */
43507ol.format.GML3.prototype.readFlatPos_ = function(node, objectStack) {
43508 var s = ol.xml.getAllTextContent(node, false);
43509 var re = /^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/;
43510 /** @type {Array.<number>} */
43511 var flatCoordinates = [];
43512 var m;
43513 while ((m = re.exec(s))) {
43514 flatCoordinates.push(parseFloat(m[1]));
43515 s = s.substr(m[0].length);
43516 }
43517 if (s !== '') {
43518 return undefined;
43519 }
43520 var context = objectStack[0];
43521 var containerSrs = context['srsName'];
43522 var axisOrientation = 'enu';
43523 if (containerSrs) {
43524 var proj = ol.proj.get(containerSrs);
43525 axisOrientation = proj.getAxisOrientation();
43526 }
43527 if (axisOrientation === 'neu') {
43528 var i, ii;
43529 for (i = 0, ii = flatCoordinates.length; i < ii; i += 3) {
43530 var y = flatCoordinates[i];
43531 var x = flatCoordinates[i + 1];
43532 flatCoordinates[i] = x;
43533 flatCoordinates[i + 1] = y;
43534 }
43535 }
43536 var len = flatCoordinates.length;
43537 if (len == 2) {
43538 flatCoordinates.push(0);
43539 }
43540 if (len === 0) {
43541 return undefined;
43542 }
43543 return flatCoordinates;
43544};
43545
43546
43547/**
43548 * @param {Node} node Node.
43549 * @param {Array.<*>} objectStack Object stack.
43550 * @private
43551 * @return {Array.<number>|undefined} Flat coordinates.
43552 */
43553ol.format.GML3.prototype.readFlatPosList_ = function(node, objectStack) {
43554 var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
43555 var context = objectStack[0];
43556 var containerSrs = context['srsName'];
43557 var containerDimension = node.parentNode.getAttribute('srsDimension');
43558 var axisOrientation = 'enu';
43559 if (containerSrs) {
43560 var proj = ol.proj.get(containerSrs);
43561 axisOrientation = proj.getAxisOrientation();
43562 }
43563 var coords = s.split(/\s+/);
43564 // The "dimension" attribute is from the GML 3.0.1 spec.
43565 var dim = 2;
43566 if (node.getAttribute('srsDimension')) {
43567 dim = ol.format.XSD.readNonNegativeIntegerString(
43568 node.getAttribute('srsDimension'));
43569 } else if (node.getAttribute('dimension')) {
43570 dim = ol.format.XSD.readNonNegativeIntegerString(
43571 node.getAttribute('dimension'));
43572 } else if (containerDimension) {
43573 dim = ol.format.XSD.readNonNegativeIntegerString(containerDimension);
43574 }
43575 var x, y, z;
43576 var flatCoordinates = [];
43577 for (var i = 0, ii = coords.length; i < ii; i += dim) {
43578 x = parseFloat(coords[i]);
43579 y = parseFloat(coords[i + 1]);
43580 z = (dim === 3) ? parseFloat(coords[i + 2]) : 0;
43581 if (axisOrientation.substr(0, 2) === 'en') {
43582 flatCoordinates.push(x, y, z);
43583 } else {
43584 flatCoordinates.push(y, x, z);
43585 }
43586 }
43587 return flatCoordinates;
43588};
43589
43590
43591/**
43592 * @const
43593 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43594 * @private
43595 */
43596ol.format.GML3.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {
43597 'http://www.opengis.net/gml': {
43598 'pos': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPos_),
43599 'posList': ol.xml.makeReplacer(ol.format.GML3.prototype.readFlatPosList_)
43600 }
43601};
43602
43603
43604/**
43605 * @const
43606 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43607 * @private
43608 */
43609ol.format.GML3.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {
43610 'http://www.opengis.net/gml': {
43611 'interior': ol.format.GML3.prototype.interiorParser_,
43612 'exterior': ol.format.GML3.prototype.exteriorParser_
43613 }
43614};
43615
43616
43617/**
43618 * @const
43619 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43620 * @private
43621 */
43622ol.format.GML3.prototype.GEOMETRY_PARSERS_ = {
43623 'http://www.opengis.net/gml': {
43624 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),
43625 'MultiPoint': ol.xml.makeReplacer(
43626 ol.format.GMLBase.prototype.readMultiPoint),
43627 'LineString': ol.xml.makeReplacer(
43628 ol.format.GMLBase.prototype.readLineString),
43629 'MultiLineString': ol.xml.makeReplacer(
43630 ol.format.GMLBase.prototype.readMultiLineString),
43631 'LinearRing': ol.xml.makeReplacer(
43632 ol.format.GMLBase.prototype.readLinearRing),
43633 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),
43634 'MultiPolygon': ol.xml.makeReplacer(
43635 ol.format.GMLBase.prototype.readMultiPolygon),
43636 'Surface': ol.xml.makeReplacer(ol.format.GML3.prototype.readSurface_),
43637 'MultiSurface': ol.xml.makeReplacer(
43638 ol.format.GML3.prototype.readMultiSurface_),
43639 'Curve': ol.xml.makeReplacer(ol.format.GML3.prototype.readCurve_),
43640 'MultiCurve': ol.xml.makeReplacer(
43641 ol.format.GML3.prototype.readMultiCurve_),
43642 'Envelope': ol.xml.makeReplacer(ol.format.GML3.prototype.readEnvelope_)
43643 }
43644};
43645
43646
43647/**
43648 * @const
43649 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43650 * @private
43651 */
43652ol.format.GML3.prototype.MULTICURVE_PARSERS_ = {
43653 'http://www.opengis.net/gml': {
43654 'curveMember': ol.xml.makeArrayPusher(
43655 ol.format.GML3.prototype.curveMemberParser_),
43656 'curveMembers': ol.xml.makeArrayPusher(
43657 ol.format.GML3.prototype.curveMemberParser_)
43658 }
43659};
43660
43661
43662/**
43663 * @const
43664 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43665 * @private
43666 */
43667ol.format.GML3.prototype.MULTISURFACE_PARSERS_ = {
43668 'http://www.opengis.net/gml': {
43669 'surfaceMember': ol.xml.makeArrayPusher(
43670 ol.format.GML3.prototype.surfaceMemberParser_),
43671 'surfaceMembers': ol.xml.makeArrayPusher(
43672 ol.format.GML3.prototype.surfaceMemberParser_)
43673 }
43674};
43675
43676
43677/**
43678 * @const
43679 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43680 * @private
43681 */
43682ol.format.GML3.prototype.CURVEMEMBER_PARSERS_ = {
43683 'http://www.opengis.net/gml': {
43684 'LineString': ol.xml.makeArrayPusher(
43685 ol.format.GMLBase.prototype.readLineString),
43686 'Curve': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readCurve_)
43687 }
43688};
43689
43690
43691/**
43692 * @const
43693 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43694 * @private
43695 */
43696ol.format.GML3.prototype.SURFACEMEMBER_PARSERS_ = {
43697 'http://www.opengis.net/gml': {
43698 'Polygon': ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readPolygon),
43699 'Surface': ol.xml.makeArrayPusher(ol.format.GML3.prototype.readSurface_)
43700 }
43701};
43702
43703
43704/**
43705 * @const
43706 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43707 * @private
43708 */
43709ol.format.GML3.prototype.SURFACE_PARSERS_ = {
43710 'http://www.opengis.net/gml': {
43711 'patches': ol.xml.makeReplacer(ol.format.GML3.prototype.readPatch_)
43712 }
43713};
43714
43715
43716/**
43717 * @const
43718 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43719 * @private
43720 */
43721ol.format.GML3.prototype.CURVE_PARSERS_ = {
43722 'http://www.opengis.net/gml': {
43723 'segments': ol.xml.makeReplacer(ol.format.GML3.prototype.readSegment_)
43724 }
43725};
43726
43727
43728/**
43729 * @const
43730 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43731 * @private
43732 */
43733ol.format.GML3.prototype.ENVELOPE_PARSERS_ = {
43734 'http://www.opengis.net/gml': {
43735 'lowerCorner': ol.xml.makeArrayPusher(
43736 ol.format.GML3.prototype.readFlatPosList_),
43737 'upperCorner': ol.xml.makeArrayPusher(
43738 ol.format.GML3.prototype.readFlatPosList_)
43739 }
43740};
43741
43742
43743/**
43744 * @const
43745 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43746 * @private
43747 */
43748ol.format.GML3.prototype.PATCHES_PARSERS_ = {
43749 'http://www.opengis.net/gml': {
43750 'PolygonPatch': ol.xml.makeReplacer(
43751 ol.format.GML3.prototype.readPolygonPatch_)
43752 }
43753};
43754
43755
43756/**
43757 * @const
43758 * @type {Object.<string, Object.<string, ol.XmlParser>>}
43759 * @private
43760 */
43761ol.format.GML3.prototype.SEGMENTS_PARSERS_ = {
43762 'http://www.opengis.net/gml': {
43763 'LineStringSegment': ol.xml.makeReplacer(
43764 ol.format.GML3.prototype.readLineStringSegment_)
43765 }
43766};
43767
43768
43769/**
43770 * @param {Node} node Node.
43771 * @param {ol.geom.Point} value Point geometry.
43772 * @param {Array.<*>} objectStack Node stack.
43773 * @private
43774 */
43775ol.format.GML3.prototype.writePos_ = function(node, value, objectStack) {
43776 var context = objectStack[objectStack.length - 1];
43777 var hasZ = context['hasZ'];
43778 var srsName = context['srsName'];
43779 var axisOrientation = 'enu';
43780 if (srsName) {
43781 axisOrientation = ol.proj.get(srsName).getAxisOrientation();
43782 }
43783 var point = value.getCoordinates();
43784 var coords;
43785 // only 2d for simple features profile
43786 if (axisOrientation.substr(0, 2) === 'en') {
43787 coords = (point[0] + ' ' + point[1]);
43788 } else {
43789 coords = (point[1] + ' ' + point[0]);
43790 }
43791 if (hasZ) {
43792 // For newly created points, Z can be undefined.
43793 var z = point[2] || 0;
43794 coords += ' ' + z;
43795 }
43796 ol.format.XSD.writeStringTextNode(node, coords);
43797};
43798
43799
43800/**
43801 * @param {Array.<number>} point Point geometry.
43802 * @param {string=} opt_srsName Optional srsName
43803 * @param {boolean=} opt_hasZ whether the geometry has a Z coordinate (is 3D) or not.
43804 * @return {string} The coords string.
43805 * @private
43806 */
43807ol.format.GML3.prototype.getCoords_ = function(point, opt_srsName, opt_hasZ) {
43808 var axisOrientation = 'enu';
43809 if (opt_srsName) {
43810 axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation();
43811 }
43812 var coords = ((axisOrientation.substr(0, 2) === 'en') ?
43813 point[0] + ' ' + point[1] :
43814 point[1] + ' ' + point[0]);
43815 if (opt_hasZ) {
43816 // For newly created points, Z can be undefined.
43817 var z = point[2] || 0;
43818 coords += ' ' + z;
43819 }
43820
43821 return coords;
43822};
43823
43824
43825/**
43826 * @param {Node} node Node.
43827 * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry.
43828 * @param {Array.<*>} objectStack Node stack.
43829 * @private
43830 */
43831ol.format.GML3.prototype.writePosList_ = function(node, value, objectStack) {
43832 var context = objectStack[objectStack.length - 1];
43833 var hasZ = context['hasZ'];
43834 var srsName = context['srsName'];
43835 // only 2d for simple features profile
43836 var points = value.getCoordinates();
43837 var len = points.length;
43838 var parts = new Array(len);
43839 var point;
43840 for (var i = 0; i < len; ++i) {
43841 point = points[i];
43842 parts[i] = this.getCoords_(point, srsName, hasZ);
43843 }
43844 ol.format.XSD.writeStringTextNode(node, parts.join(' '));
43845};
43846
43847
43848/**
43849 * @param {Node} node Node.
43850 * @param {ol.geom.Point} geometry Point geometry.
43851 * @param {Array.<*>} objectStack Node stack.
43852 * @private
43853 */
43854ol.format.GML3.prototype.writePoint_ = function(node, geometry, objectStack) {
43855 var context = objectStack[objectStack.length - 1];
43856 var srsName = context['srsName'];
43857 if (srsName) {
43858 node.setAttribute('srsName', srsName);
43859 }
43860 var pos = ol.xml.createElementNS(node.namespaceURI, 'pos');
43861 node.appendChild(pos);
43862 this.writePos_(pos, geometry, objectStack);
43863};
43864
43865
43866/**
43867 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
43868 * @private
43869 */
43870ol.format.GML3.ENVELOPE_SERIALIZERS_ = {
43871 'http://www.opengis.net/gml': {
43872 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
43873 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
43874 }
43875};
43876
43877
43878/**
43879 * @param {Node} node Node.
43880 * @param {ol.Extent} extent Extent.
43881 * @param {Array.<*>} objectStack Node stack.
43882 */
43883ol.format.GML3.prototype.writeEnvelope = function(node, extent, objectStack) {
43884 var context = objectStack[objectStack.length - 1];
43885 var srsName = context['srsName'];
43886 if (srsName) {
43887 node.setAttribute('srsName', srsName);
43888 }
43889 var keys = ['lowerCorner', 'upperCorner'];
43890 var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]];
43891 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
43892 ({node: node}), ol.format.GML3.ENVELOPE_SERIALIZERS_,
43893 ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
43894 values,
43895 objectStack, keys, this);
43896};
43897
43898
43899/**
43900 * @param {Node} node Node.
43901 * @param {ol.geom.LinearRing} geometry LinearRing geometry.
43902 * @param {Array.<*>} objectStack Node stack.
43903 * @private
43904 */
43905ol.format.GML3.prototype.writeLinearRing_ = function(node, geometry, objectStack) {
43906 var context = objectStack[objectStack.length - 1];
43907 var srsName = context['srsName'];
43908 if (srsName) {
43909 node.setAttribute('srsName', srsName);
43910 }
43911 var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');
43912 node.appendChild(posList);
43913 this.writePosList_(posList, geometry, objectStack);
43914};
43915
43916
43917/**
43918 * @param {*} value Value.
43919 * @param {Array.<*>} objectStack Object stack.
43920 * @param {string=} opt_nodeName Node name.
43921 * @return {Node} Node.
43922 * @private
43923 */
43924ol.format.GML3.prototype.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
43925 var context = objectStack[objectStack.length - 1];
43926 var parentNode = context.node;
43927 var exteriorWritten = context['exteriorWritten'];
43928 if (exteriorWritten === undefined) {
43929 context['exteriorWritten'] = true;
43930 }
43931 return ol.xml.createElementNS(parentNode.namespaceURI,
43932 exteriorWritten !== undefined ? 'interior' : 'exterior');
43933};
43934
43935
43936/**
43937 * @param {Node} node Node.
43938 * @param {ol.geom.Polygon} geometry Polygon geometry.
43939 * @param {Array.<*>} objectStack Node stack.
43940 * @private
43941 */
43942ol.format.GML3.prototype.writeSurfaceOrPolygon_ = function(node, geometry, objectStack) {
43943 var context = objectStack[objectStack.length - 1];
43944 var hasZ = context['hasZ'];
43945 var srsName = context['srsName'];
43946 if (node.nodeName !== 'PolygonPatch' && srsName) {
43947 node.setAttribute('srsName', srsName);
43948 }
43949 if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') {
43950 var rings = geometry.getLinearRings();
43951 ol.xml.pushSerializeAndPop(
43952 {node: node, hasZ: hasZ, srsName: srsName},
43953 ol.format.GML3.RING_SERIALIZERS_,
43954 this.RING_NODE_FACTORY_,
43955 rings, objectStack, undefined, this);
43956 } else if (node.nodeName === 'Surface') {
43957 var patches = ol.xml.createElementNS(node.namespaceURI, 'patches');
43958 node.appendChild(patches);
43959 this.writeSurfacePatches_(
43960 patches, geometry, objectStack);
43961 }
43962};
43963
43964
43965/**
43966 * @param {Node} node Node.
43967 * @param {ol.geom.LineString} geometry LineString geometry.
43968 * @param {Array.<*>} objectStack Node stack.
43969 * @private
43970 */
43971ol.format.GML3.prototype.writeCurveOrLineString_ = function(node, geometry, objectStack) {
43972 var context = objectStack[objectStack.length - 1];
43973 var srsName = context['srsName'];
43974 if (node.nodeName !== 'LineStringSegment' && srsName) {
43975 node.setAttribute('srsName', srsName);
43976 }
43977 if (node.nodeName === 'LineString' ||
43978 node.nodeName === 'LineStringSegment') {
43979 var posList = ol.xml.createElementNS(node.namespaceURI, 'posList');
43980 node.appendChild(posList);
43981 this.writePosList_(posList, geometry, objectStack);
43982 } else if (node.nodeName === 'Curve') {
43983 var segments = ol.xml.createElementNS(node.namespaceURI, 'segments');
43984 node.appendChild(segments);
43985 this.writeCurveSegments_(segments,
43986 geometry, objectStack);
43987 }
43988};
43989
43990
43991/**
43992 * @param {Node} node Node.
43993 * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.
43994 * @param {Array.<*>} objectStack Node stack.
43995 * @private
43996 */
43997ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_ = function(node, geometry, objectStack) {
43998 var context = objectStack[objectStack.length - 1];
43999 var hasZ = context['hasZ'];
44000 var srsName = context['srsName'];
44001 var surface = context['surface'];
44002 if (srsName) {
44003 node.setAttribute('srsName', srsName);
44004 }
44005 var polygons = geometry.getPolygons();
44006 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName, surface: surface},
44007 ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_,
44008 this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons,
44009 objectStack, undefined, this);
44010};
44011
44012
44013/**
44014 * @param {Node} node Node.
44015 * @param {ol.geom.MultiPoint} geometry MultiPoint geometry.
44016 * @param {Array.<*>} objectStack Node stack.
44017 * @private
44018 */
44019ol.format.GML3.prototype.writeMultiPoint_ = function(node, geometry,
44020 objectStack) {
44021 var context = objectStack[objectStack.length - 1];
44022 var srsName = context['srsName'];
44023 var hasZ = context['hasZ'];
44024 if (srsName) {
44025 node.setAttribute('srsName', srsName);
44026 }
44027 var points = geometry.getPoints();
44028 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName},
44029 ol.format.GML3.POINTMEMBER_SERIALIZERS_,
44030 ol.xml.makeSimpleNodeFactory('pointMember'), points,
44031 objectStack, undefined, this);
44032};
44033
44034
44035/**
44036 * @param {Node} node Node.
44037 * @param {ol.geom.MultiLineString} geometry MultiLineString geometry.
44038 * @param {Array.<*>} objectStack Node stack.
44039 * @private
44040 */
44041ol.format.GML3.prototype.writeMultiCurveOrLineString_ = function(node, geometry, objectStack) {
44042 var context = objectStack[objectStack.length - 1];
44043 var hasZ = context['hasZ'];
44044 var srsName = context['srsName'];
44045 var curve = context['curve'];
44046 if (srsName) {
44047 node.setAttribute('srsName', srsName);
44048 }
44049 var lines = geometry.getLineStrings();
44050 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName, curve: curve},
44051 ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_,
44052 this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines,
44053 objectStack, undefined, this);
44054};
44055
44056
44057/**
44058 * @param {Node} node Node.
44059 * @param {ol.geom.LinearRing} ring LinearRing geometry.
44060 * @param {Array.<*>} objectStack Node stack.
44061 * @private
44062 */
44063ol.format.GML3.prototype.writeRing_ = function(node, ring, objectStack) {
44064 var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing');
44065 node.appendChild(linearRing);
44066 this.writeLinearRing_(linearRing, ring, objectStack);
44067};
44068
44069
44070/**
44071 * @param {Node} node Node.
44072 * @param {ol.geom.Polygon} polygon Polygon geometry.
44073 * @param {Array.<*>} objectStack Node stack.
44074 * @private
44075 */
44076ol.format.GML3.prototype.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) {
44077 var child = this.GEOMETRY_NODE_FACTORY_(
44078 polygon, objectStack);
44079 if (child) {
44080 node.appendChild(child);
44081 this.writeSurfaceOrPolygon_(child, polygon, objectStack);
44082 }
44083};
44084
44085
44086/**
44087 * @param {Node} node Node.
44088 * @param {ol.geom.Point} point Point geometry.
44089 * @param {Array.<*>} objectStack Node stack.
44090 * @private
44091 */
44092ol.format.GML3.prototype.writePointMember_ = function(node, point, objectStack) {
44093 var child = ol.xml.createElementNS(node.namespaceURI, 'Point');
44094 node.appendChild(child);
44095 this.writePoint_(child, point, objectStack);
44096};
44097
44098
44099/**
44100 * @param {Node} node Node.
44101 * @param {ol.geom.LineString} line LineString geometry.
44102 * @param {Array.<*>} objectStack Node stack.
44103 * @private
44104 */
44105ol.format.GML3.prototype.writeLineStringOrCurveMember_ = function(node, line, objectStack) {
44106 var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack);
44107 if (child) {
44108 node.appendChild(child);
44109 this.writeCurveOrLineString_(child, line, objectStack);
44110 }
44111};
44112
44113
44114/**
44115 * @param {Node} node Node.
44116 * @param {ol.geom.Polygon} polygon Polygon geometry.
44117 * @param {Array.<*>} objectStack Node stack.
44118 * @private
44119 */
44120ol.format.GML3.prototype.writeSurfacePatches_ = function(node, polygon, objectStack) {
44121 var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch');
44122 node.appendChild(child);
44123 this.writeSurfaceOrPolygon_(child, polygon, objectStack);
44124};
44125
44126
44127/**
44128 * @param {Node} node Node.
44129 * @param {ol.geom.LineString} line LineString geometry.
44130 * @param {Array.<*>} objectStack Node stack.
44131 * @private
44132 */
44133ol.format.GML3.prototype.writeCurveSegments_ = function(node, line, objectStack) {
44134 var child = ol.xml.createElementNS(node.namespaceURI,
44135 'LineStringSegment');
44136 node.appendChild(child);
44137 this.writeCurveOrLineString_(child, line, objectStack);
44138};
44139
44140
44141/**
44142 * @param {Node} node Node.
44143 * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
44144 * @param {Array.<*>} objectStack Node stack.
44145 */
44146ol.format.GML3.prototype.writeGeometryElement = function(node, geometry, objectStack) {
44147 var context = /** @type {olx.format.WriteOptions} */ (objectStack[objectStack.length - 1]);
44148 var item = ol.obj.assign({}, context);
44149 item.node = node;
44150 var value;
44151 if (Array.isArray(geometry)) {
44152 if (context.dataProjection) {
44153 value = ol.proj.transformExtent(
44154 geometry, context.featureProjection, context.dataProjection);
44155 } else {
44156 value = geometry;
44157 }
44158 } else {
44159 value =
44160 ol.format.Feature.transformWithOptions(/** @type {ol.geom.Geometry} */ (geometry), true, context);
44161 }
44162 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
44163 (item), ol.format.GML3.GEOMETRY_SERIALIZERS_,
44164 this.GEOMETRY_NODE_FACTORY_, [value],
44165 objectStack, undefined, this);
44166};
44167
44168
44169/**
44170 * @param {Node} node Node.
44171 * @param {ol.Feature} feature Feature.
44172 * @param {Array.<*>} objectStack Node stack.
44173 */
44174ol.format.GML3.prototype.writeFeatureElement = function(node, feature, objectStack) {
44175 var fid = feature.getId();
44176 if (fid) {
44177 node.setAttribute('fid', fid);
44178 }
44179 var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);
44180 var featureNS = context['featureNS'];
44181 var geometryName = feature.getGeometryName();
44182 if (!context.serializers) {
44183 context.serializers = {};
44184 context.serializers[featureNS] = {};
44185 }
44186 var properties = feature.getProperties();
44187 var keys = [], values = [];
44188 for (var key in properties) {
44189 var value = properties[key];
44190 if (value !== null) {
44191 keys.push(key);
44192 values.push(value);
44193 if (key == geometryName || value instanceof ol.geom.Geometry) {
44194 if (!(key in context.serializers[featureNS])) {
44195 context.serializers[featureNS][key] = ol.xml.makeChildAppender(
44196 this.writeGeometryElement, this);
44197 }
44198 } else {
44199 if (!(key in context.serializers[featureNS])) {
44200 context.serializers[featureNS][key] = ol.xml.makeChildAppender(
44201 ol.format.XSD.writeStringTextNode);
44202 }
44203 }
44204 }
44205 }
44206 var item = ol.obj.assign({}, context);
44207 item.node = node;
44208 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
44209 (item), context.serializers,
44210 ol.xml.makeSimpleNodeFactory(undefined, featureNS),
44211 values,
44212 objectStack, keys);
44213};
44214
44215
44216/**
44217 * @param {Node} node Node.
44218 * @param {Array.<ol.Feature>} features Features.
44219 * @param {Array.<*>} objectStack Node stack.
44220 * @private
44221 */
44222ol.format.GML3.prototype.writeFeatureMembers_ = function(node, features, objectStack) {
44223 var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);
44224 var featureType = context['featureType'];
44225 var featureNS = context['featureNS'];
44226 var serializers = {};
44227 serializers[featureNS] = {};
44228 serializers[featureNS][featureType] = ol.xml.makeChildAppender(
44229 this.writeFeatureElement, this);
44230 var item = ol.obj.assign({}, context);
44231 item.node = node;
44232 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
44233 (item),
44234 serializers,
44235 ol.xml.makeSimpleNodeFactory(featureType, featureNS), features,
44236 objectStack);
44237};
44238
44239
44240/**
44241 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
44242 * @private
44243 */
44244ol.format.GML3.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = {
44245 'http://www.opengis.net/gml': {
44246 'surfaceMember': ol.xml.makeChildAppender(
44247 ol.format.GML3.prototype.writeSurfaceOrPolygonMember_),
44248 'polygonMember': ol.xml.makeChildAppender(
44249 ol.format.GML3.prototype.writeSurfaceOrPolygonMember_)
44250 }
44251};
44252
44253
44254/**
44255 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
44256 * @private
44257 */
44258ol.format.GML3.POINTMEMBER_SERIALIZERS_ = {
44259 'http://www.opengis.net/gml': {
44260 'pointMember': ol.xml.makeChildAppender(
44261 ol.format.GML3.prototype.writePointMember_)
44262 }
44263};
44264
44265
44266/**
44267 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
44268 * @private
44269 */
44270ol.format.GML3.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = {
44271 'http://www.opengis.net/gml': {
44272 'lineStringMember': ol.xml.makeChildAppender(
44273 ol.format.GML3.prototype.writeLineStringOrCurveMember_),
44274 'curveMember': ol.xml.makeChildAppender(
44275 ol.format.GML3.prototype.writeLineStringOrCurveMember_)
44276 }
44277};
44278
44279
44280/**
44281 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
44282 * @private
44283 */
44284ol.format.GML3.RING_SERIALIZERS_ = {
44285 'http://www.opengis.net/gml': {
44286 'exterior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_),
44287 'interior': ol.xml.makeChildAppender(ol.format.GML3.prototype.writeRing_)
44288 }
44289};
44290
44291
44292/**
44293 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
44294 * @private
44295 */
44296ol.format.GML3.GEOMETRY_SERIALIZERS_ = {
44297 'http://www.opengis.net/gml': {
44298 'Curve': ol.xml.makeChildAppender(
44299 ol.format.GML3.prototype.writeCurveOrLineString_),
44300 'MultiCurve': ol.xml.makeChildAppender(
44301 ol.format.GML3.prototype.writeMultiCurveOrLineString_),
44302 'Point': ol.xml.makeChildAppender(ol.format.GML3.prototype.writePoint_),
44303 'MultiPoint': ol.xml.makeChildAppender(
44304 ol.format.GML3.prototype.writeMultiPoint_),
44305 'LineString': ol.xml.makeChildAppender(
44306 ol.format.GML3.prototype.writeCurveOrLineString_),
44307 'MultiLineString': ol.xml.makeChildAppender(
44308 ol.format.GML3.prototype.writeMultiCurveOrLineString_),
44309 'LinearRing': ol.xml.makeChildAppender(
44310 ol.format.GML3.prototype.writeLinearRing_),
44311 'Polygon': ol.xml.makeChildAppender(
44312 ol.format.GML3.prototype.writeSurfaceOrPolygon_),
44313 'MultiPolygon': ol.xml.makeChildAppender(
44314 ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),
44315 'Surface': ol.xml.makeChildAppender(
44316 ol.format.GML3.prototype.writeSurfaceOrPolygon_),
44317 'MultiSurface': ol.xml.makeChildAppender(
44318 ol.format.GML3.prototype.writeMultiSurfaceOrPolygon_),
44319 'Envelope': ol.xml.makeChildAppender(
44320 ol.format.GML3.prototype.writeEnvelope)
44321 }
44322};
44323
44324
44325/**
44326 * @const
44327 * @type {Object.<string, string>}
44328 * @private
44329 */
44330ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = {
44331 'MultiLineString': 'lineStringMember',
44332 'MultiCurve': 'curveMember',
44333 'MultiPolygon': 'polygonMember',
44334 'MultiSurface': 'surfaceMember'
44335};
44336
44337
44338/**
44339 * @const
44340 * @param {*} value Value.
44341 * @param {Array.<*>} objectStack Object stack.
44342 * @param {string=} opt_nodeName Node name.
44343 * @return {Node|undefined} Node.
44344 * @private
44345 */
44346ol.format.GML3.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
44347 var parentNode = objectStack[objectStack.length - 1].node;
44348 return ol.xml.createElementNS('http://www.opengis.net/gml',
44349 ol.format.GML3.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]);
44350};
44351
44352
44353/**
44354 * @const
44355 * @param {*} value Value.
44356 * @param {Array.<*>} objectStack Object stack.
44357 * @param {string=} opt_nodeName Node name.
44358 * @return {Node|undefined} Node.
44359 * @private
44360 */
44361ol.format.GML3.prototype.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
44362 var context = objectStack[objectStack.length - 1];
44363 var multiSurface = context['multiSurface'];
44364 var surface = context['surface'];
44365 var curve = context['curve'];
44366 var multiCurve = context['multiCurve'];
44367 var nodeName;
44368 if (!Array.isArray(value)) {
44369 nodeName = /** @type {ol.geom.Geometry} */ (value).getType();
44370 if (nodeName === 'MultiPolygon' && multiSurface === true) {
44371 nodeName = 'MultiSurface';
44372 } else if (nodeName === 'Polygon' && surface === true) {
44373 nodeName = 'Surface';
44374 } else if (nodeName === 'LineString' && curve === true) {
44375 nodeName = 'Curve';
44376 } else if (nodeName === 'MultiLineString' && multiCurve === true) {
44377 nodeName = 'MultiCurve';
44378 }
44379 } else {
44380 nodeName = 'Envelope';
44381 }
44382 return ol.xml.createElementNS('http://www.opengis.net/gml',
44383 nodeName);
44384};
44385
44386
44387/**
44388 * Encode a geometry in GML 3.1.1 Simple Features.
44389 *
44390 * @param {ol.geom.Geometry} geometry Geometry.
44391 * @param {olx.format.WriteOptions=} opt_options Options.
44392 * @return {Node} Node.
44393 * @override
44394 * @api
44395 */
44396ol.format.GML3.prototype.writeGeometryNode = function(geometry, opt_options) {
44397 opt_options = this.adaptOptions(opt_options);
44398 var geom = ol.xml.createElementNS('http://www.opengis.net/gml', 'geom');
44399 var context = {node: geom, hasZ: this.hasZ, srsName: this.srsName,
44400 curve: this.curve_, surface: this.surface_,
44401 multiSurface: this.multiSurface_, multiCurve: this.multiCurve_};
44402 if (opt_options) {
44403 ol.obj.assign(context, opt_options);
44404 }
44405 this.writeGeometryElement(geom, geometry, [context]);
44406 return geom;
44407};
44408
44409
44410/**
44411 * Encode an array of features in GML 3.1.1 Simple Features.
44412 *
44413 * @function
44414 * @param {Array.<ol.Feature>} features Features.
44415 * @param {olx.format.WriteOptions=} opt_options Options.
44416 * @return {string} Result.
44417 * @api
44418 */
44419ol.format.GML3.prototype.writeFeatures;
44420
44421
44422/**
44423 * Encode an array of features in the GML 3.1.1 format as an XML node.
44424 *
44425 * @param {Array.<ol.Feature>} features Features.
44426 * @param {olx.format.WriteOptions=} opt_options Options.
44427 * @return {Node} Node.
44428 * @override
44429 * @api
44430 */
44431ol.format.GML3.prototype.writeFeaturesNode = function(features, opt_options) {
44432 opt_options = this.adaptOptions(opt_options);
44433 var node = ol.xml.createElementNS('http://www.opengis.net/gml',
44434 'featureMembers');
44435 ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
44436 'xsi:schemaLocation', this.schemaLocation);
44437 var context = {
44438 srsName: this.srsName,
44439 hasZ: this.hasZ,
44440 curve: this.curve_,
44441 surface: this.surface_,
44442 multiSurface: this.multiSurface_,
44443 multiCurve: this.multiCurve_,
44444 featureNS: this.featureNS,
44445 featureType: this.featureType
44446 };
44447 if (opt_options) {
44448 ol.obj.assign(context, opt_options);
44449 }
44450 this.writeFeatureMembers_(node, features, [context]);
44451 return node;
44452};
44453
44454goog.provide('ol.format.GML');
44455
44456goog.require('ol.format.GML3');
44457
44458
44459/**
44460 * @classdesc
44461 * Feature format for reading and writing data in the GML format
44462 * version 3.1.1.
44463 * Currently only supports GML 3.1.1 Simple Features profile.
44464 *
44465 * @constructor
44466 * @param {olx.format.GMLOptions=} opt_options
44467 * Optional configuration object.
44468 * @extends {ol.format.GMLBase}
44469 * @api
44470 */
44471ol.format.GML = ol.format.GML3;
44472
44473
44474/**
44475 * Encode an array of features in GML 3.1.1 Simple Features.
44476 *
44477 * @function
44478 * @param {Array.<ol.Feature>} features Features.
44479 * @param {olx.format.WriteOptions=} opt_options Options.
44480 * @return {string} Result.
44481 * @api
44482 */
44483ol.format.GML.prototype.writeFeatures;
44484
44485
44486/**
44487 * Encode an array of features in the GML 3.1.1 format as an XML node.
44488 *
44489 * @function
44490 * @param {Array.<ol.Feature>} features Features.
44491 * @param {olx.format.WriteOptions=} opt_options Options.
44492 * @return {Node} Node.
44493 * @api
44494 */
44495ol.format.GML.prototype.writeFeaturesNode;
44496
44497goog.provide('ol.format.GML2');
44498
44499goog.require('ol');
44500goog.require('ol.extent');
44501goog.require('ol.format.Feature');
44502goog.require('ol.format.GMLBase');
44503goog.require('ol.format.XSD');
44504goog.require('ol.geom.Geometry');
44505goog.require('ol.obj');
44506goog.require('ol.proj');
44507goog.require('ol.xml');
44508
44509
44510/**
44511 * @classdesc
44512 * Feature format for reading and writing data in the GML format,
44513 * version 2.1.2.
44514 *
44515 * @constructor
44516 * @param {olx.format.GMLOptions=} opt_options Optional configuration object.
44517 * @extends {ol.format.GMLBase}
44518 * @api
44519 */
44520ol.format.GML2 = function(opt_options) {
44521 var options = /** @type {olx.format.GMLOptions} */
44522 (opt_options ? opt_options : {});
44523
44524 ol.format.GMLBase.call(this, options);
44525
44526 this.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][
44527 'featureMember'] =
44528 ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);
44529
44530 /**
44531 * @inheritDoc
44532 */
44533 this.schemaLocation = options.schemaLocation ?
44534 options.schemaLocation : ol.format.GML2.schemaLocation_;
44535
44536};
44537ol.inherits(ol.format.GML2, ol.format.GMLBase);
44538
44539
44540/**
44541 * @const
44542 * @type {string}
44543 * @private
44544 */
44545ol.format.GML2.schemaLocation_ = ol.format.GMLBase.GMLNS +
44546 ' http://schemas.opengis.net/gml/2.1.2/feature.xsd';
44547
44548
44549/**
44550 * @param {Node} node Node.
44551 * @param {Array.<*>} objectStack Object stack.
44552 * @private
44553 * @return {Array.<number>|undefined} Flat coordinates.
44554 */
44555ol.format.GML2.prototype.readFlatCoordinates_ = function(node, objectStack) {
44556 var s = ol.xml.getAllTextContent(node, false).replace(/^\s*|\s*$/g, '');
44557 var context = /** @type {ol.XmlNodeStackItem} */ (objectStack[0]);
44558 var containerSrs = context['srsName'];
44559 var axisOrientation = 'enu';
44560 if (containerSrs) {
44561 var proj = ol.proj.get(containerSrs);
44562 if (proj) {
44563 axisOrientation = proj.getAxisOrientation();
44564 }
44565 }
44566 var coordsGroups = s.trim().split(/\s+/);
44567 var x, y, z;
44568 var flatCoordinates = [];
44569 for (var i = 0, ii = coordsGroups.length; i < ii; i++) {
44570 var coords = coordsGroups[i].split(/,+/);
44571 x = parseFloat(coords[0]);
44572 y = parseFloat(coords[1]);
44573 z = (coords.length === 3) ? parseFloat(coords[2]) : 0;
44574 if (axisOrientation.substr(0, 2) === 'en') {
44575 flatCoordinates.push(x, y, z);
44576 } else {
44577 flatCoordinates.push(y, x, z);
44578 }
44579 }
44580 return flatCoordinates;
44581};
44582
44583
44584/**
44585 * @param {Node} node Node.
44586 * @param {Array.<*>} objectStack Object stack.
44587 * @private
44588 * @return {ol.Extent|undefined} Envelope.
44589 */
44590ol.format.GML2.prototype.readBox_ = function(node, objectStack) {
44591 /** @type {Array.<number>} */
44592 var flatCoordinates = ol.xml.pushParseAndPop([null],
44593 this.BOX_PARSERS_, node, objectStack, this);
44594 return ol.extent.createOrUpdate(flatCoordinates[1][0],
44595 flatCoordinates[1][1], flatCoordinates[1][3],
44596 flatCoordinates[1][4]);
44597};
44598
44599
44600/**
44601 * @param {Node} node Node.
44602 * @param {Array.<*>} objectStack Object stack.
44603 * @private
44604 */
44605ol.format.GML2.prototype.innerBoundaryIsParser_ = function(node, objectStack) {
44606 /** @type {Array.<number>|undefined} */
44607 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
44608 this.RING_PARSERS, node, objectStack, this);
44609 if (flatLinearRing) {
44610 var flatLinearRings = /** @type {Array.<Array.<number>>} */
44611 (objectStack[objectStack.length - 1]);
44612 flatLinearRings.push(flatLinearRing);
44613 }
44614};
44615
44616
44617/**
44618 * @param {Node} node Node.
44619 * @param {Array.<*>} objectStack Object stack.
44620 * @private
44621 */
44622ol.format.GML2.prototype.outerBoundaryIsParser_ = function(node, objectStack) {
44623 /** @type {Array.<number>|undefined} */
44624 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
44625 this.RING_PARSERS, node, objectStack, this);
44626 if (flatLinearRing) {
44627 var flatLinearRings = /** @type {Array.<Array.<number>>} */
44628 (objectStack[objectStack.length - 1]);
44629 flatLinearRings[0] = flatLinearRing;
44630 }
44631};
44632
44633
44634/**
44635 * @const
44636 * @type {Object.<string, Object.<string, ol.XmlParser>>}
44637 * @private
44638 */
44639ol.format.GML2.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS_ = {
44640 'http://www.opengis.net/gml': {
44641 'coordinates': ol.xml.makeReplacer(
44642 ol.format.GML2.prototype.readFlatCoordinates_)
44643 }
44644};
44645
44646
44647/**
44648 * @const
44649 * @type {Object.<string, Object.<string, ol.XmlParser>>}
44650 * @private
44651 */
44652ol.format.GML2.prototype.FLAT_LINEAR_RINGS_PARSERS_ = {
44653 'http://www.opengis.net/gml': {
44654 'innerBoundaryIs': ol.format.GML2.prototype.innerBoundaryIsParser_,
44655 'outerBoundaryIs': ol.format.GML2.prototype.outerBoundaryIsParser_
44656 }
44657};
44658
44659
44660/**
44661 * @const
44662 * @type {Object.<string, Object.<string, ol.XmlParser>>}
44663 * @private
44664 */
44665ol.format.GML2.prototype.BOX_PARSERS_ = {
44666 'http://www.opengis.net/gml': {
44667 'coordinates': ol.xml.makeArrayPusher(
44668 ol.format.GML2.prototype.readFlatCoordinates_)
44669 }
44670};
44671
44672
44673/**
44674 * @const
44675 * @type {Object.<string, Object.<string, ol.XmlParser>>}
44676 * @private
44677 */
44678ol.format.GML2.prototype.GEOMETRY_PARSERS_ = {
44679 'http://www.opengis.net/gml': {
44680 'Point': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPoint),
44681 'MultiPoint': ol.xml.makeReplacer(
44682 ol.format.GMLBase.prototype.readMultiPoint),
44683 'LineString': ol.xml.makeReplacer(
44684 ol.format.GMLBase.prototype.readLineString),
44685 'MultiLineString': ol.xml.makeReplacer(
44686 ol.format.GMLBase.prototype.readMultiLineString),
44687 'LinearRing': ol.xml.makeReplacer(
44688 ol.format.GMLBase.prototype.readLinearRing),
44689 'Polygon': ol.xml.makeReplacer(ol.format.GMLBase.prototype.readPolygon),
44690 'MultiPolygon': ol.xml.makeReplacer(
44691 ol.format.GMLBase.prototype.readMultiPolygon),
44692 'Box': ol.xml.makeReplacer(ol.format.GML2.prototype.readBox_)
44693 }
44694};
44695
44696
44697/**
44698 * @const
44699 * @param {*} value Value.
44700 * @param {Array.<*>} objectStack Object stack.
44701 * @param {string=} opt_nodeName Node name.
44702 * @return {Node|undefined} Node.
44703 * @private
44704 */
44705ol.format.GML2.prototype.GEOMETRY_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
44706 var context = objectStack[objectStack.length - 1];
44707 var multiSurface = context['multiSurface'];
44708 var surface = context['surface'];
44709 var multiCurve = context['multiCurve'];
44710 var nodeName;
44711 if (!Array.isArray(value)) {
44712 nodeName = /** @type {ol.geom.Geometry} */ (value).getType();
44713 if (nodeName === 'MultiPolygon' && multiSurface === true) {
44714 nodeName = 'MultiSurface';
44715 } else if (nodeName === 'Polygon' && surface === true) {
44716 nodeName = 'Surface';
44717 } else if (nodeName === 'MultiLineString' && multiCurve === true) {
44718 nodeName = 'MultiCurve';
44719 }
44720 } else {
44721 nodeName = 'Envelope';
44722 }
44723 return ol.xml.createElementNS('http://www.opengis.net/gml',
44724 nodeName);
44725};
44726
44727
44728/**
44729 * @param {Node} node Node.
44730 * @param {ol.Feature} feature Feature.
44731 * @param {Array.<*>} objectStack Node stack.
44732 */
44733ol.format.GML2.prototype.writeFeatureElement = function(node, feature, objectStack) {
44734 var fid = feature.getId();
44735 if (fid) {
44736 node.setAttribute('fid', fid);
44737 }
44738 var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);
44739 var featureNS = context['featureNS'];
44740 var geometryName = feature.getGeometryName();
44741 if (!context.serializers) {
44742 context.serializers = {};
44743 context.serializers[featureNS] = {};
44744 }
44745 var properties = feature.getProperties();
44746 var keys = [], values = [];
44747 for (var key in properties) {
44748 var value = properties[key];
44749 if (value !== null) {
44750 keys.push(key);
44751 values.push(value);
44752 if (key == geometryName || value instanceof ol.geom.Geometry) {
44753 if (!(key in context.serializers[featureNS])) {
44754 context.serializers[featureNS][key] = ol.xml.makeChildAppender(
44755 this.writeGeometryElement, this);
44756 }
44757 } else {
44758 if (!(key in context.serializers[featureNS])) {
44759 context.serializers[featureNS][key] = ol.xml.makeChildAppender(
44760 ol.format.XSD.writeStringTextNode);
44761 }
44762 }
44763 }
44764 }
44765 var item = ol.obj.assign({}, context);
44766 item.node = node;
44767 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
44768 (item), context.serializers,
44769 ol.xml.makeSimpleNodeFactory(undefined, featureNS),
44770 values,
44771 objectStack, keys);
44772};
44773
44774
44775/**
44776 * @param {Node} node Node.
44777 * @param {ol.geom.Geometry|ol.Extent} geometry Geometry.
44778 * @param {Array.<*>} objectStack Node stack.
44779 */
44780ol.format.GML2.prototype.writeGeometryElement = function(node, geometry, objectStack) {
44781 var context = /** @type {olx.format.WriteOptions} */ (objectStack[objectStack.length - 1]);
44782 var item = ol.obj.assign({}, context);
44783 item.node = node;
44784 var value;
44785 if (Array.isArray(geometry)) {
44786 if (context.dataProjection) {
44787 value = ol.proj.transformExtent(
44788 geometry, context.featureProjection, context.dataProjection);
44789 } else {
44790 value = geometry;
44791 }
44792 } else {
44793 value =
44794 ol.format.Feature.transformWithOptions(/** @type {ol.geom.Geometry} */ (geometry), true, context);
44795 }
44796 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
44797 (item), ol.format.GML2.GEOMETRY_SERIALIZERS_,
44798 this.GEOMETRY_NODE_FACTORY_, [value],
44799 objectStack, undefined, this);
44800};
44801
44802
44803/**
44804 * @param {Node} node Node.
44805 * @param {ol.geom.LineString} geometry LineString geometry.
44806 * @param {Array.<*>} objectStack Node stack.
44807 * @private
44808 */
44809ol.format.GML2.prototype.writeCurveOrLineString_ = function(node, geometry, objectStack) {
44810 var context = objectStack[objectStack.length - 1];
44811 var srsName = context['srsName'];
44812 if (node.nodeName !== 'LineStringSegment' && srsName) {
44813 node.setAttribute('srsName', srsName);
44814 }
44815 if (node.nodeName === 'LineString' ||
44816 node.nodeName === 'LineStringSegment') {
44817 var coordinates = this.createCoordinatesNode_(node.namespaceURI);
44818 node.appendChild(coordinates);
44819 this.writeCoordinates_(coordinates, geometry, objectStack);
44820 } else if (node.nodeName === 'Curve') {
44821 var segments = ol.xml.createElementNS(node.namespaceURI, 'segments');
44822 node.appendChild(segments);
44823 this.writeCurveSegments_(segments,
44824 geometry, objectStack);
44825 }
44826};
44827
44828
44829/**
44830 * @param {string} namespaceURI XML namespace.
44831 * @returns {Node} coordinates node.
44832 * @private
44833 */
44834ol.format.GML2.prototype.createCoordinatesNode_ = function(namespaceURI) {
44835 var coordinates = ol.xml.createElementNS(namespaceURI, 'coordinates');
44836 coordinates.setAttribute('decimal', '.');
44837 coordinates.setAttribute('cs', ',');
44838 coordinates.setAttribute('ts', ' ');
44839
44840 return coordinates;
44841};
44842
44843
44844/**
44845 * @param {Node} node Node.
44846 * @param {ol.geom.LineString|ol.geom.LinearRing} value Geometry.
44847 * @param {Array.<*>} objectStack Node stack.
44848 * @private
44849 */
44850ol.format.GML2.prototype.writeCoordinates_ = function(node, value, objectStack) {
44851 var context = objectStack[objectStack.length - 1];
44852 var hasZ = context['hasZ'];
44853 var srsName = context['srsName'];
44854 // only 2d for simple features profile
44855 var points = value.getCoordinates();
44856 var len = points.length;
44857 var parts = new Array(len);
44858 var point;
44859 for (var i = 0; i < len; ++i) {
44860 point = points[i];
44861 parts[i] = this.getCoords_(point, srsName, hasZ);
44862 }
44863 ol.format.XSD.writeStringTextNode(node, parts.join(' '));
44864};
44865
44866
44867/**
44868 * @param {Node} node Node.
44869 * @param {ol.geom.LineString} line LineString geometry.
44870 * @param {Array.<*>} objectStack Node stack.
44871 * @private
44872 */
44873ol.format.GML2.prototype.writeCurveSegments_ = function(node, line, objectStack) {
44874 var child = ol.xml.createElementNS(node.namespaceURI,
44875 'LineStringSegment');
44876 node.appendChild(child);
44877 this.writeCurveOrLineString_(child, line, objectStack);
44878};
44879
44880
44881/**
44882 * @param {Node} node Node.
44883 * @param {ol.geom.Polygon} geometry Polygon geometry.
44884 * @param {Array.<*>} objectStack Node stack.
44885 * @private
44886 */
44887ol.format.GML2.prototype.writeSurfaceOrPolygon_ = function(node, geometry, objectStack) {
44888 var context = objectStack[objectStack.length - 1];
44889 var hasZ = context['hasZ'];
44890 var srsName = context['srsName'];
44891 if (node.nodeName !== 'PolygonPatch' && srsName) {
44892 node.setAttribute('srsName', srsName);
44893 }
44894 if (node.nodeName === 'Polygon' || node.nodeName === 'PolygonPatch') {
44895 var rings = geometry.getLinearRings();
44896 ol.xml.pushSerializeAndPop(
44897 {node: node, hasZ: hasZ, srsName: srsName},
44898 ol.format.GML2.RING_SERIALIZERS_,
44899 this.RING_NODE_FACTORY_,
44900 rings, objectStack, undefined, this);
44901 } else if (node.nodeName === 'Surface') {
44902 var patches = ol.xml.createElementNS(node.namespaceURI, 'patches');
44903 node.appendChild(patches);
44904 this.writeSurfacePatches_(
44905 patches, geometry, objectStack);
44906 }
44907};
44908
44909
44910/**
44911 * @param {*} value Value.
44912 * @param {Array.<*>} objectStack Object stack.
44913 * @param {string=} opt_nodeName Node name.
44914 * @return {Node} Node.
44915 * @private
44916 */
44917ol.format.GML2.prototype.RING_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
44918 var context = objectStack[objectStack.length - 1];
44919 var parentNode = context.node;
44920 var exteriorWritten = context['exteriorWritten'];
44921 if (exteriorWritten === undefined) {
44922 context['exteriorWritten'] = true;
44923 }
44924 return ol.xml.createElementNS(parentNode.namespaceURI,
44925 exteriorWritten !== undefined ? 'innerBoundaryIs' : 'outerBoundaryIs');
44926};
44927
44928
44929/**
44930 * @param {Node} node Node.
44931 * @param {ol.geom.Polygon} polygon Polygon geometry.
44932 * @param {Array.<*>} objectStack Node stack.
44933 * @private
44934 */
44935ol.format.GML2.prototype.writeSurfacePatches_ = function(node, polygon, objectStack) {
44936 var child = ol.xml.createElementNS(node.namespaceURI, 'PolygonPatch');
44937 node.appendChild(child);
44938 this.writeSurfaceOrPolygon_(child, polygon, objectStack);
44939};
44940
44941
44942/**
44943 * @param {Node} node Node.
44944 * @param {ol.geom.LinearRing} ring LinearRing geometry.
44945 * @param {Array.<*>} objectStack Node stack.
44946 * @private
44947 */
44948ol.format.GML2.prototype.writeRing_ = function(node, ring, objectStack) {
44949 var linearRing = ol.xml.createElementNS(node.namespaceURI, 'LinearRing');
44950 node.appendChild(linearRing);
44951 this.writeLinearRing_(linearRing, ring, objectStack);
44952};
44953
44954
44955/**
44956 * @param {Array.<number>} point Point geometry.
44957 * @param {string=} opt_srsName Optional srsName
44958 * @param {boolean=} opt_hasZ whether the geometry has a Z coordinate (is 3D) or not.
44959 * @return {string} The coords string.
44960 * @private
44961 */
44962ol.format.GML2.prototype.getCoords_ = function(point, opt_srsName, opt_hasZ) {
44963 var axisOrientation = 'enu';
44964 if (opt_srsName) {
44965 axisOrientation = ol.proj.get(opt_srsName).getAxisOrientation();
44966 }
44967 var coords = ((axisOrientation.substr(0, 2) === 'en') ?
44968 point[0] + ',' + point[1] :
44969 point[1] + ',' + point[0]);
44970 if (opt_hasZ) {
44971 // For newly created points, Z can be undefined.
44972 var z = point[2] || 0;
44973 coords += ',' + z;
44974 }
44975
44976 return coords;
44977};
44978
44979
44980/**
44981 * @param {Node} node Node.
44982 * @param {ol.geom.MultiLineString} geometry MultiLineString geometry.
44983 * @param {Array.<*>} objectStack Node stack.
44984 * @private
44985 */
44986ol.format.GML2.prototype.writeMultiCurveOrLineString_ = function(node, geometry, objectStack) {
44987 var context = objectStack[objectStack.length - 1];
44988 var hasZ = context['hasZ'];
44989 var srsName = context['srsName'];
44990 var curve = context['curve'];
44991 if (srsName) {
44992 node.setAttribute('srsName', srsName);
44993 }
44994 var lines = geometry.getLineStrings();
44995 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName, curve: curve},
44996 ol.format.GML2.LINESTRINGORCURVEMEMBER_SERIALIZERS_,
44997 this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, lines,
44998 objectStack, undefined, this);
44999};
45000
45001
45002/**
45003 * @param {Node} node Node.
45004 * @param {ol.geom.Point} geometry Point geometry.
45005 * @param {Array.<*>} objectStack Node stack.
45006 * @private
45007 */
45008ol.format.GML2.prototype.writePoint_ = function(node, geometry, objectStack) {
45009 var context = objectStack[objectStack.length - 1];
45010 var hasZ = context['hasZ'];
45011 var srsName = context['srsName'];
45012 if (srsName) {
45013 node.setAttribute('srsName', srsName);
45014 }
45015 var coordinates = this.createCoordinatesNode_(node.namespaceURI);
45016 node.appendChild(coordinates);
45017 var point = geometry.getCoordinates();
45018 var coord = this.getCoords_(point, srsName, hasZ);
45019 ol.format.XSD.writeStringTextNode(coordinates, coord);
45020};
45021
45022
45023/**
45024 * @param {Node} node Node.
45025 * @param {ol.geom.MultiPoint} geometry MultiPoint geometry.
45026 * @param {Array.<*>} objectStack Node stack.
45027 * @private
45028 */
45029ol.format.GML2.prototype.writeMultiPoint_ = function(node, geometry,
45030 objectStack) {
45031 var context = objectStack[objectStack.length - 1];
45032 var hasZ = context['hasZ'];
45033 var srsName = context['srsName'];
45034 if (srsName) {
45035 node.setAttribute('srsName', srsName);
45036 }
45037 var points = geometry.getPoints();
45038 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName},
45039 ol.format.GML2.POINTMEMBER_SERIALIZERS_,
45040 ol.xml.makeSimpleNodeFactory('pointMember'), points,
45041 objectStack, undefined, this);
45042};
45043
45044
45045/**
45046 * @param {Node} node Node.
45047 * @param {ol.geom.Point} point Point geometry.
45048 * @param {Array.<*>} objectStack Node stack.
45049 * @private
45050 */
45051ol.format.GML2.prototype.writePointMember_ = function(node, point, objectStack) {
45052 var child = ol.xml.createElementNS(node.namespaceURI, 'Point');
45053 node.appendChild(child);
45054 this.writePoint_(child, point, objectStack);
45055};
45056
45057
45058/**
45059 * @param {Node} node Node.
45060 * @param {ol.geom.LineString} line LineString geometry.
45061 * @param {Array.<*>} objectStack Node stack.
45062 * @private
45063 */
45064ol.format.GML2.prototype.writeLineStringOrCurveMember_ = function(node, line, objectStack) {
45065 var child = this.GEOMETRY_NODE_FACTORY_(line, objectStack);
45066 if (child) {
45067 node.appendChild(child);
45068 this.writeCurveOrLineString_(child, line, objectStack);
45069 }
45070};
45071
45072
45073/**
45074 * @param {Node} node Node.
45075 * @param {ol.geom.LinearRing} geometry LinearRing geometry.
45076 * @param {Array.<*>} objectStack Node stack.
45077 * @private
45078 */
45079ol.format.GML2.prototype.writeLinearRing_ = function(node, geometry, objectStack) {
45080 var context = objectStack[objectStack.length - 1];
45081 var srsName = context['srsName'];
45082 if (srsName) {
45083 node.setAttribute('srsName', srsName);
45084 }
45085 var coordinates = this.createCoordinatesNode_(node.namespaceURI);
45086 node.appendChild(coordinates);
45087 this.writeCoordinates_(coordinates, geometry, objectStack);
45088};
45089
45090
45091/**
45092 * @param {Node} node Node.
45093 * @param {ol.geom.MultiPolygon} geometry MultiPolygon geometry.
45094 * @param {Array.<*>} objectStack Node stack.
45095 * @private
45096 */
45097ol.format.GML2.prototype.writeMultiSurfaceOrPolygon_ = function(node, geometry, objectStack) {
45098 var context = objectStack[objectStack.length - 1];
45099 var hasZ = context['hasZ'];
45100 var srsName = context['srsName'];
45101 var surface = context['surface'];
45102 if (srsName) {
45103 node.setAttribute('srsName', srsName);
45104 }
45105 var polygons = geometry.getPolygons();
45106 ol.xml.pushSerializeAndPop({node: node, hasZ: hasZ, srsName: srsName, surface: surface},
45107 ol.format.GML2.SURFACEORPOLYGONMEMBER_SERIALIZERS_,
45108 this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_, polygons,
45109 objectStack, undefined, this);
45110};
45111
45112
45113/**
45114 * @param {Node} node Node.
45115 * @param {ol.geom.Polygon} polygon Polygon geometry.
45116 * @param {Array.<*>} objectStack Node stack.
45117 * @private
45118 */
45119ol.format.GML2.prototype.writeSurfaceOrPolygonMember_ = function(node, polygon, objectStack) {
45120 var child = this.GEOMETRY_NODE_FACTORY_(
45121 polygon, objectStack);
45122 if (child) {
45123 node.appendChild(child);
45124 this.writeSurfaceOrPolygon_(child, polygon, objectStack);
45125 }
45126};
45127
45128
45129/**
45130 * @param {Node} node Node.
45131 * @param {ol.Extent} extent Extent.
45132 * @param {Array.<*>} objectStack Node stack.
45133 * @private
45134 */
45135ol.format.GML2.prototype.writeEnvelope = function(node, extent, objectStack) {
45136 var context = objectStack[objectStack.length - 1];
45137 var srsName = context['srsName'];
45138 if (srsName) {
45139 node.setAttribute('srsName', srsName);
45140 }
45141 var keys = ['lowerCorner', 'upperCorner'];
45142 var values = [extent[0] + ' ' + extent[1], extent[2] + ' ' + extent[3]];
45143 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
45144 ({node: node}), ol.format.GML2.ENVELOPE_SERIALIZERS_,
45145 ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
45146 values,
45147 objectStack, keys, this);
45148};
45149
45150
45151/**
45152 * @const
45153 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45154 * @private
45155 */
45156ol.format.GML2.GEOMETRY_SERIALIZERS_ = {
45157 'http://www.opengis.net/gml': {
45158 'Curve': ol.xml.makeChildAppender(
45159 ol.format.GML2.prototype.writeCurveOrLineString_),
45160 'MultiCurve': ol.xml.makeChildAppender(
45161 ol.format.GML2.prototype.writeMultiCurveOrLineString_),
45162 'Point': ol.xml.makeChildAppender(ol.format.GML2.prototype.writePoint_),
45163 'MultiPoint': ol.xml.makeChildAppender(
45164 ol.format.GML2.prototype.writeMultiPoint_),
45165 'LineString': ol.xml.makeChildAppender(
45166 ol.format.GML2.prototype.writeCurveOrLineString_),
45167 'MultiLineString': ol.xml.makeChildAppender(
45168 ol.format.GML2.prototype.writeMultiCurveOrLineString_),
45169 'LinearRing': ol.xml.makeChildAppender(
45170 ol.format.GML2.prototype.writeLinearRing_),
45171 'Polygon': ol.xml.makeChildAppender(
45172 ol.format.GML2.prototype.writeSurfaceOrPolygon_),
45173 'MultiPolygon': ol.xml.makeChildAppender(
45174 ol.format.GML2.prototype.writeMultiSurfaceOrPolygon_),
45175 'Surface': ol.xml.makeChildAppender(
45176 ol.format.GML2.prototype.writeSurfaceOrPolygon_),
45177 'MultiSurface': ol.xml.makeChildAppender(
45178 ol.format.GML2.prototype.writeMultiSurfaceOrPolygon_),
45179 'Envelope': ol.xml.makeChildAppender(
45180 ol.format.GML2.prototype.writeEnvelope)
45181 }
45182};
45183
45184
45185/**
45186 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45187 * @private
45188 */
45189ol.format.GML2.RING_SERIALIZERS_ = {
45190 'http://www.opengis.net/gml': {
45191 'outerBoundaryIs': ol.xml.makeChildAppender(ol.format.GML2.prototype.writeRing_),
45192 'innerBoundaryIs': ol.xml.makeChildAppender(ol.format.GML2.prototype.writeRing_)
45193 }
45194};
45195
45196
45197/**
45198 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45199 * @private
45200 */
45201ol.format.GML2.POINTMEMBER_SERIALIZERS_ = {
45202 'http://www.opengis.net/gml': {
45203 'pointMember': ol.xml.makeChildAppender(
45204 ol.format.GML2.prototype.writePointMember_)
45205 }
45206};
45207
45208
45209/**
45210 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45211 * @private
45212 */
45213ol.format.GML2.LINESTRINGORCURVEMEMBER_SERIALIZERS_ = {
45214 'http://www.opengis.net/gml': {
45215 'lineStringMember': ol.xml.makeChildAppender(
45216 ol.format.GML2.prototype.writeLineStringOrCurveMember_),
45217 'curveMember': ol.xml.makeChildAppender(
45218 ol.format.GML2.prototype.writeLineStringOrCurveMember_)
45219 }
45220};
45221
45222
45223/**
45224 * @const
45225 * @param {*} value Value.
45226 * @param {Array.<*>} objectStack Object stack.
45227 * @param {string=} opt_nodeName Node name.
45228 * @return {Node|undefined} Node.
45229 * @private
45230 */
45231ol.format.GML2.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
45232 var parentNode = objectStack[objectStack.length - 1].node;
45233 return ol.xml.createElementNS('http://www.opengis.net/gml',
45234 ol.format.GML2.MULTIGEOMETRY_TO_MEMBER_NODENAME_[parentNode.nodeName]);
45235};
45236
45237/**
45238 * @const
45239 * @type {Object.<string, string>}
45240 * @private
45241 */
45242ol.format.GML2.MULTIGEOMETRY_TO_MEMBER_NODENAME_ = {
45243 'MultiLineString': 'lineStringMember',
45244 'MultiCurve': 'curveMember',
45245 'MultiPolygon': 'polygonMember',
45246 'MultiSurface': 'surfaceMember'
45247};
45248
45249
45250/**
45251 * @const
45252 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45253 * @private
45254 */
45255ol.format.GML2.SURFACEORPOLYGONMEMBER_SERIALIZERS_ = {
45256 'http://www.opengis.net/gml': {
45257 'surfaceMember': ol.xml.makeChildAppender(
45258 ol.format.GML2.prototype.writeSurfaceOrPolygonMember_),
45259 'polygonMember': ol.xml.makeChildAppender(
45260 ol.format.GML2.prototype.writeSurfaceOrPolygonMember_)
45261 }
45262};
45263
45264
45265/**
45266 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45267 * @private
45268 */
45269ol.format.GML2.ENVELOPE_SERIALIZERS_ = {
45270 'http://www.opengis.net/gml': {
45271 'lowerCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
45272 'upperCorner': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
45273 }
45274};
45275
45276goog.provide('ol.format.GPX');
45277
45278goog.require('ol');
45279goog.require('ol.Feature');
45280goog.require('ol.array');
45281goog.require('ol.format.Feature');
45282goog.require('ol.format.XMLFeature');
45283goog.require('ol.format.XSD');
45284goog.require('ol.geom.GeometryLayout');
45285goog.require('ol.geom.LineString');
45286goog.require('ol.geom.MultiLineString');
45287goog.require('ol.geom.Point');
45288goog.require('ol.proj');
45289goog.require('ol.xml');
45290
45291
45292/**
45293 * @classdesc
45294 * Feature format for reading and writing data in the GPX format.
45295 *
45296 * @constructor
45297 * @extends {ol.format.XMLFeature}
45298 * @param {olx.format.GPXOptions=} opt_options Options.
45299 * @api
45300 */
45301ol.format.GPX = function(opt_options) {
45302
45303 var options = opt_options ? opt_options : {};
45304
45305 ol.format.XMLFeature.call(this);
45306
45307 /**
45308 * @inheritDoc
45309 */
45310 this.defaultDataProjection = ol.proj.get('EPSG:4326');
45311
45312 /**
45313 * @type {function(ol.Feature, Node)|undefined}
45314 * @private
45315 */
45316 this.readExtensions_ = options.readExtensions;
45317};
45318ol.inherits(ol.format.GPX, ol.format.XMLFeature);
45319
45320
45321/**
45322 * @const
45323 * @private
45324 * @type {Array.<string>}
45325 */
45326ol.format.GPX.NAMESPACE_URIS_ = [
45327 null,
45328 'http://www.topografix.com/GPX/1/0',
45329 'http://www.topografix.com/GPX/1/1'
45330];
45331
45332
45333/**
45334 * @const
45335 * @type {string}
45336 * @private
45337 */
45338ol.format.GPX.SCHEMA_LOCATION_ = 'http://www.topografix.com/GPX/1/1 ' +
45339 'http://www.topografix.com/GPX/1/1/gpx.xsd';
45340
45341
45342/**
45343 * @param {Array.<number>} flatCoordinates Flat coordinates.
45344 * @param {ol.LayoutOptions} layoutOptions Layout options.
45345 * @param {Node} node Node.
45346 * @param {Object} values Values.
45347 * @private
45348 * @return {Array.<number>} Flat coordinates.
45349 */
45350ol.format.GPX.appendCoordinate_ = function(flatCoordinates, layoutOptions, node, values) {
45351 flatCoordinates.push(
45352 parseFloat(node.getAttribute('lon')),
45353 parseFloat(node.getAttribute('lat')));
45354 if ('ele' in values) {
45355 flatCoordinates.push(/** @type {number} */ (values['ele']));
45356 delete values['ele'];
45357 layoutOptions.hasZ = true;
45358 } else {
45359 flatCoordinates.push(0);
45360 }
45361 if ('time' in values) {
45362 flatCoordinates.push(/** @type {number} */ (values['time']));
45363 delete values['time'];
45364 layoutOptions.hasM = true;
45365 } else {
45366 flatCoordinates.push(0);
45367 }
45368 return flatCoordinates;
45369};
45370
45371
45372/**
45373 * Choose GeometryLayout based on flags in layoutOptions and adjust flatCoordinates
45374 * and ends arrays by shrinking them accordingly (removing unused zero entries).
45375 *
45376 * @param {ol.LayoutOptions} layoutOptions Layout options.
45377 * @param {Array.<number>} flatCoordinates Flat coordinates.
45378 * @param {Array.<number>=} ends Ends.
45379 * @return {ol.geom.GeometryLayout} Layout.
45380 */
45381ol.format.GPX.applyLayoutOptions_ = function(layoutOptions, flatCoordinates, ends) {
45382 var layout = ol.geom.GeometryLayout.XY;
45383 var stride = 2;
45384 if (layoutOptions.hasZ && layoutOptions.hasM) {
45385 layout = ol.geom.GeometryLayout.XYZM;
45386 stride = 4;
45387 } else if (layoutOptions.hasZ) {
45388 layout = ol.geom.GeometryLayout.XYZ;
45389 stride = 3;
45390 } else if (layoutOptions.hasM) {
45391 layout = ol.geom.GeometryLayout.XYM;
45392 stride = 3;
45393 }
45394 if (stride !== 4) {
45395 var i, ii;
45396 for (i = 0, ii = flatCoordinates.length / 4; i < ii; i++) {
45397 flatCoordinates[i * stride] = flatCoordinates[i * 4];
45398 flatCoordinates[i * stride + 1] = flatCoordinates[i * 4 + 1];
45399 if (layoutOptions.hasZ) {
45400 flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 2];
45401 }
45402 if (layoutOptions.hasM) {
45403 flatCoordinates[i * stride + 2] = flatCoordinates[i * 4 + 3];
45404 }
45405 }
45406 flatCoordinates.length = flatCoordinates.length / 4 * stride;
45407 if (ends) {
45408 for (i = 0, ii = ends.length; i < ii; i++) {
45409 ends[i] = ends[i] / 4 * stride;
45410 }
45411 }
45412 }
45413 return layout;
45414};
45415
45416
45417/**
45418 * @param {Node} node Node.
45419 * @param {Array.<*>} objectStack Object stack.
45420 * @private
45421 */
45422ol.format.GPX.parseLink_ = function(node, objectStack) {
45423 var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
45424 var href = node.getAttribute('href');
45425 if (href !== null) {
45426 values['link'] = href;
45427 }
45428 ol.xml.parseNode(ol.format.GPX.LINK_PARSERS_, node, objectStack);
45429};
45430
45431
45432/**
45433 * @param {Node} node Node.
45434 * @param {Array.<*>} objectStack Object stack.
45435 * @private
45436 */
45437ol.format.GPX.parseExtensions_ = function(node, objectStack) {
45438 var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
45439 values['extensionsNode_'] = node;
45440};
45441
45442
45443/**
45444 * @param {Node} node Node.
45445 * @param {Array.<*>} objectStack Object stack.
45446 * @private
45447 */
45448ol.format.GPX.parseRtePt_ = function(node, objectStack) {
45449 var values = ol.xml.pushParseAndPop(
45450 {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack);
45451 if (values) {
45452 var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
45453 var flatCoordinates = /** @type {Array.<number>} */
45454 (rteValues['flatCoordinates']);
45455 var layoutOptions = /** @type {ol.LayoutOptions} */
45456 (rteValues['layoutOptions']);
45457 ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);
45458 }
45459};
45460
45461
45462/**
45463 * @param {Node} node Node.
45464 * @param {Array.<*>} objectStack Object stack.
45465 * @private
45466 */
45467ol.format.GPX.parseTrkPt_ = function(node, objectStack) {
45468 var values = ol.xml.pushParseAndPop(
45469 {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack);
45470 if (values) {
45471 var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]);
45472 var flatCoordinates = /** @type {Array.<number>} */
45473 (trkValues['flatCoordinates']);
45474 var layoutOptions = /** @type {ol.LayoutOptions} */
45475 (trkValues['layoutOptions']);
45476 ol.format.GPX.appendCoordinate_(flatCoordinates, layoutOptions, node, values);
45477 }
45478};
45479
45480
45481/**
45482 * @param {Node} node Node.
45483 * @param {Array.<*>} objectStack Object stack.
45484 * @private
45485 */
45486ol.format.GPX.parseTrkSeg_ = function(node, objectStack) {
45487 var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
45488 ol.xml.parseNode(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack);
45489 var flatCoordinates = /** @type {Array.<number>} */
45490 (values['flatCoordinates']);
45491 var ends = /** @type {Array.<number>} */ (values['ends']);
45492 ends.push(flatCoordinates.length);
45493};
45494
45495
45496/**
45497 * @param {Node} node Node.
45498 * @param {Array.<*>} objectStack Object stack.
45499 * @private
45500 * @return {ol.Feature|undefined} Track.
45501 */
45502ol.format.GPX.readRte_ = function(node, objectStack) {
45503 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
45504 var values = ol.xml.pushParseAndPop({
45505 'flatCoordinates': [],
45506 'layoutOptions': {}
45507 }, ol.format.GPX.RTE_PARSERS_, node, objectStack);
45508 if (!values) {
45509 return undefined;
45510 }
45511 var flatCoordinates = /** @type {Array.<number>} */
45512 (values['flatCoordinates']);
45513 delete values['flatCoordinates'];
45514 var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);
45515 delete values['layoutOptions'];
45516 var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates);
45517 var geometry = new ol.geom.LineString(null);
45518 geometry.setFlatCoordinates(layout, flatCoordinates);
45519 ol.format.Feature.transformWithOptions(geometry, false, options);
45520 var feature = new ol.Feature(geometry);
45521 feature.setProperties(values);
45522 return feature;
45523};
45524
45525
45526/**
45527 * @param {Node} node Node.
45528 * @param {Array.<*>} objectStack Object stack.
45529 * @private
45530 * @return {ol.Feature|undefined} Track.
45531 */
45532ol.format.GPX.readTrk_ = function(node, objectStack) {
45533 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
45534 var values = ol.xml.pushParseAndPop({
45535 'flatCoordinates': [],
45536 'ends': [],
45537 'layoutOptions': {}
45538 }, ol.format.GPX.TRK_PARSERS_, node, objectStack);
45539 if (!values) {
45540 return undefined;
45541 }
45542 var flatCoordinates = /** @type {Array.<number>} */
45543 (values['flatCoordinates']);
45544 delete values['flatCoordinates'];
45545 var ends = /** @type {Array.<number>} */ (values['ends']);
45546 delete values['ends'];
45547 var layoutOptions = /** @type {ol.LayoutOptions} */ (values['layoutOptions']);
45548 delete values['layoutOptions'];
45549 var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, flatCoordinates, ends);
45550 var geometry = new ol.geom.MultiLineString(null);
45551 geometry.setFlatCoordinates(layout, flatCoordinates, ends);
45552 ol.format.Feature.transformWithOptions(geometry, false, options);
45553 var feature = new ol.Feature(geometry);
45554 feature.setProperties(values);
45555 return feature;
45556};
45557
45558
45559/**
45560 * @param {Node} node Node.
45561 * @param {Array.<*>} objectStack Object stack.
45562 * @private
45563 * @return {ol.Feature|undefined} Waypoint.
45564 */
45565ol.format.GPX.readWpt_ = function(node, objectStack) {
45566 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
45567 var values = ol.xml.pushParseAndPop(
45568 {}, ol.format.GPX.WPT_PARSERS_, node, objectStack);
45569 if (!values) {
45570 return undefined;
45571 }
45572 var layoutOptions = /** @type {ol.LayoutOptions} */ ({});
45573 var coordinates = ol.format.GPX.appendCoordinate_([], layoutOptions, node, values);
45574 var layout = ol.format.GPX.applyLayoutOptions_(layoutOptions, coordinates);
45575 var geometry = new ol.geom.Point(coordinates, layout);
45576 ol.format.Feature.transformWithOptions(geometry, false, options);
45577 var feature = new ol.Feature(geometry);
45578 feature.setProperties(values);
45579 return feature;
45580};
45581
45582
45583/**
45584 * @const
45585 * @type {Object.<string, function(Node, Array.<*>): (ol.Feature|undefined)>}
45586 * @private
45587 */
45588ol.format.GPX.FEATURE_READER_ = {
45589 'rte': ol.format.GPX.readRte_,
45590 'trk': ol.format.GPX.readTrk_,
45591 'wpt': ol.format.GPX.readWpt_
45592};
45593
45594
45595/**
45596 * @const
45597 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45598 * @private
45599 */
45600ol.format.GPX.GPX_PARSERS_ = ol.xml.makeStructureNS(
45601 ol.format.GPX.NAMESPACE_URIS_, {
45602 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_),
45603 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_),
45604 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_)
45605 });
45606
45607
45608/**
45609 * @const
45610 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45611 * @private
45612 */
45613ol.format.GPX.LINK_PARSERS_ = ol.xml.makeStructureNS(
45614 ol.format.GPX.NAMESPACE_URIS_, {
45615 'text':
45616 ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'),
45617 'type':
45618 ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType')
45619 });
45620
45621
45622/**
45623 * @const
45624 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45625 * @private
45626 */
45627ol.format.GPX.RTE_PARSERS_ = ol.xml.makeStructureNS(
45628 ol.format.GPX.NAMESPACE_URIS_, {
45629 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45630 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45631 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45632 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45633 'link': ol.format.GPX.parseLink_,
45634 'number':
45635 ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
45636 'extensions': ol.format.GPX.parseExtensions_,
45637 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45638 'rtept': ol.format.GPX.parseRtePt_
45639 });
45640
45641
45642/**
45643 * @const
45644 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45645 * @private
45646 */
45647ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeStructureNS(
45648 ol.format.GPX.NAMESPACE_URIS_, {
45649 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45650 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
45651 });
45652
45653
45654/**
45655 * @const
45656 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45657 * @private
45658 */
45659ol.format.GPX.TRK_PARSERS_ = ol.xml.makeStructureNS(
45660 ol.format.GPX.NAMESPACE_URIS_, {
45661 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45662 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45663 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45664 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45665 'link': ol.format.GPX.parseLink_,
45666 'number':
45667 ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
45668 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45669 'extensions': ol.format.GPX.parseExtensions_,
45670 'trkseg': ol.format.GPX.parseTrkSeg_
45671 });
45672
45673
45674/**
45675 * @const
45676 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45677 * @private
45678 */
45679ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeStructureNS(
45680 ol.format.GPX.NAMESPACE_URIS_, {
45681 'trkpt': ol.format.GPX.parseTrkPt_
45682 });
45683
45684
45685/**
45686 * @const
45687 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45688 * @private
45689 */
45690ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeStructureNS(
45691 ol.format.GPX.NAMESPACE_URIS_, {
45692 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45693 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime)
45694 });
45695
45696
45697/**
45698 * @const
45699 * @type {Object.<string, Object.<string, ol.XmlParser>>}
45700 * @private
45701 */
45702ol.format.GPX.WPT_PARSERS_ = ol.xml.makeStructureNS(
45703 ol.format.GPX.NAMESPACE_URIS_, {
45704 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45705 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime),
45706 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45707 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45708 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45709 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45710 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45711 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45712 'link': ol.format.GPX.parseLink_,
45713 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45714 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45715 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
45716 'sat': ol.xml.makeObjectPropertySetter(
45717 ol.format.XSD.readNonNegativeInteger),
45718 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45719 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45720 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45721 'ageofdgpsdata':
45722 ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
45723 'dgpsid':
45724 ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger),
45725 'extensions': ol.format.GPX.parseExtensions_
45726 });
45727
45728
45729/**
45730 * @param {Array.<ol.Feature>} features List of features.
45731 * @private
45732 */
45733ol.format.GPX.prototype.handleReadExtensions_ = function(features) {
45734 if (!features) {
45735 features = [];
45736 }
45737 for (var i = 0, ii = features.length; i < ii; ++i) {
45738 var feature = features[i];
45739 if (this.readExtensions_) {
45740 var extensionsNode = feature.get('extensionsNode_') || null;
45741 this.readExtensions_(feature, extensionsNode);
45742 }
45743 feature.set('extensionsNode_', undefined);
45744 }
45745};
45746
45747
45748/**
45749 * Read the first feature from a GPX source.
45750 * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
45751 * into MultiLineString. Any properties on route and track waypoints are ignored.
45752 *
45753 * @function
45754 * @param {Document|Node|Object|string} source Source.
45755 * @param {olx.format.ReadOptions=} opt_options Read options.
45756 * @return {ol.Feature} Feature.
45757 * @api
45758 */
45759ol.format.GPX.prototype.readFeature;
45760
45761
45762/**
45763 * @inheritDoc
45764 */
45765ol.format.GPX.prototype.readFeatureFromNode = function(node, opt_options) {
45766 if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
45767 return null;
45768 }
45769 var featureReader = ol.format.GPX.FEATURE_READER_[node.localName];
45770 if (!featureReader) {
45771 return null;
45772 }
45773 var feature = featureReader(node, [this.getReadOptions(node, opt_options)]);
45774 if (!feature) {
45775 return null;
45776 }
45777 this.handleReadExtensions_([feature]);
45778 return feature;
45779};
45780
45781
45782/**
45783 * Read all features from a GPX source.
45784 * Routes (`<rte>`) are converted into LineString geometries, and tracks (`<trk>`)
45785 * into MultiLineString. Any properties on route and track waypoints are ignored.
45786 *
45787 * @function
45788 * @param {Document|Node|Object|string} source Source.
45789 * @param {olx.format.ReadOptions=} opt_options Read options.
45790 * @return {Array.<ol.Feature>} Features.
45791 * @api
45792 */
45793ol.format.GPX.prototype.readFeatures;
45794
45795
45796/**
45797 * @inheritDoc
45798 */
45799ol.format.GPX.prototype.readFeaturesFromNode = function(node, opt_options) {
45800 if (!ol.array.includes(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI)) {
45801 return [];
45802 }
45803 if (node.localName == 'gpx') {
45804 /** @type {Array.<ol.Feature>} */
45805 var features = ol.xml.pushParseAndPop([], ol.format.GPX.GPX_PARSERS_,
45806 node, [this.getReadOptions(node, opt_options)]);
45807 if (features) {
45808 this.handleReadExtensions_(features);
45809 return features;
45810 } else {
45811 return [];
45812 }
45813 }
45814 return [];
45815};
45816
45817
45818/**
45819 * Read the projection from a GPX source.
45820 *
45821 * @function
45822 * @param {Document|Node|Object|string} source Source.
45823 * @return {ol.proj.Projection} Projection.
45824 * @api
45825 */
45826ol.format.GPX.prototype.readProjection;
45827
45828
45829/**
45830 * @param {Node} node Node.
45831 * @param {string} value Value for the link's `href` attribute.
45832 * @param {Array.<*>} objectStack Node stack.
45833 * @private
45834 */
45835ol.format.GPX.writeLink_ = function(node, value, objectStack) {
45836 node.setAttribute('href', value);
45837 var context = objectStack[objectStack.length - 1];
45838 var properties = context['properties'];
45839 var link = [
45840 properties['linkText'],
45841 properties['linkType']
45842 ];
45843 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ ({node: node}),
45844 ol.format.GPX.LINK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
45845 link, objectStack, ol.format.GPX.LINK_SEQUENCE_);
45846};
45847
45848
45849/**
45850 * @param {Node} node Node.
45851 * @param {ol.Coordinate} coordinate Coordinate.
45852 * @param {Array.<*>} objectStack Object stack.
45853 * @private
45854 */
45855ol.format.GPX.writeWptType_ = function(node, coordinate, objectStack) {
45856 var context = objectStack[objectStack.length - 1];
45857 var parentNode = context.node;
45858 var namespaceURI = parentNode.namespaceURI;
45859 var properties = context['properties'];
45860 //FIXME Projection handling
45861 ol.xml.setAttributeNS(node, null, 'lat', coordinate[1]);
45862 ol.xml.setAttributeNS(node, null, 'lon', coordinate[0]);
45863 var geometryLayout = context['geometryLayout'];
45864 switch (geometryLayout) {
45865 case ol.geom.GeometryLayout.XYZM:
45866 if (coordinate[3] !== 0) {
45867 properties['time'] = coordinate[3];
45868 }
45869 // fall through
45870 case ol.geom.GeometryLayout.XYZ:
45871 if (coordinate[2] !== 0) {
45872 properties['ele'] = coordinate[2];
45873 }
45874 break;
45875 case ol.geom.GeometryLayout.XYM:
45876 if (coordinate[2] !== 0) {
45877 properties['time'] = coordinate[2];
45878 }
45879 break;
45880 default:
45881 // pass
45882 }
45883 var orderedKeys = (node.nodeName == 'rtept') ?
45884 ol.format.GPX.RTEPT_TYPE_SEQUENCE_[namespaceURI] :
45885 ol.format.GPX.WPT_TYPE_SEQUENCE_[namespaceURI];
45886 var values = ol.xml.makeSequence(properties, orderedKeys);
45887 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
45888 ({node: node, 'properties': properties}),
45889 ol.format.GPX.WPT_TYPE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
45890 values, objectStack, orderedKeys);
45891};
45892
45893
45894/**
45895 * @param {Node} node Node.
45896 * @param {ol.Feature} feature Feature.
45897 * @param {Array.<*>} objectStack Object stack.
45898 * @private
45899 */
45900ol.format.GPX.writeRte_ = function(node, feature, objectStack) {
45901 var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
45902 var properties = feature.getProperties();
45903 var context = {node: node, 'properties': properties};
45904 var geometry = feature.getGeometry();
45905 if (geometry) {
45906 geometry = /** @type {ol.geom.LineString} */
45907 (ol.format.Feature.transformWithOptions(geometry, true, options));
45908 context['geometryLayout'] = geometry.getLayout();
45909 properties['rtept'] = geometry.getCoordinates();
45910 }
45911 var parentNode = objectStack[objectStack.length - 1].node;
45912 var orderedKeys = ol.format.GPX.RTE_SEQUENCE_[parentNode.namespaceURI];
45913 var values = ol.xml.makeSequence(properties, orderedKeys);
45914 ol.xml.pushSerializeAndPop(context,
45915 ol.format.GPX.RTE_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
45916 values, objectStack, orderedKeys);
45917};
45918
45919
45920/**
45921 * @param {Node} node Node.
45922 * @param {ol.Feature} feature Feature.
45923 * @param {Array.<*>} objectStack Object stack.
45924 * @private
45925 */
45926ol.format.GPX.writeTrk_ = function(node, feature, objectStack) {
45927 var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
45928 var properties = feature.getProperties();
45929 /** @type {ol.XmlNodeStackItem} */
45930 var context = {node: node, 'properties': properties};
45931 var geometry = feature.getGeometry();
45932 if (geometry) {
45933 geometry = /** @type {ol.geom.MultiLineString} */
45934 (ol.format.Feature.transformWithOptions(geometry, true, options));
45935 properties['trkseg'] = geometry.getLineStrings();
45936 }
45937 var parentNode = objectStack[objectStack.length - 1].node;
45938 var orderedKeys = ol.format.GPX.TRK_SEQUENCE_[parentNode.namespaceURI];
45939 var values = ol.xml.makeSequence(properties, orderedKeys);
45940 ol.xml.pushSerializeAndPop(context,
45941 ol.format.GPX.TRK_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
45942 values, objectStack, orderedKeys);
45943};
45944
45945
45946/**
45947 * @param {Node} node Node.
45948 * @param {ol.geom.LineString} lineString LineString.
45949 * @param {Array.<*>} objectStack Object stack.
45950 * @private
45951 */
45952ol.format.GPX.writeTrkSeg_ = function(node, lineString, objectStack) {
45953 /** @type {ol.XmlNodeStackItem} */
45954 var context = {node: node, 'geometryLayout': lineString.getLayout(),
45955 'properties': {}};
45956 ol.xml.pushSerializeAndPop(context,
45957 ol.format.GPX.TRKSEG_SERIALIZERS_, ol.format.GPX.TRKSEG_NODE_FACTORY_,
45958 lineString.getCoordinates(), objectStack);
45959};
45960
45961
45962/**
45963 * @param {Node} node Node.
45964 * @param {ol.Feature} feature Feature.
45965 * @param {Array.<*>} objectStack Object stack.
45966 * @private
45967 */
45968ol.format.GPX.writeWpt_ = function(node, feature, objectStack) {
45969 var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
45970 var context = objectStack[objectStack.length - 1];
45971 context['properties'] = feature.getProperties();
45972 var geometry = feature.getGeometry();
45973 if (geometry) {
45974 geometry = /** @type {ol.geom.Point} */
45975 (ol.format.Feature.transformWithOptions(geometry, true, options));
45976 context['geometryLayout'] = geometry.getLayout();
45977 ol.format.GPX.writeWptType_(node, geometry.getCoordinates(), objectStack);
45978 }
45979};
45980
45981
45982/**
45983 * @const
45984 * @type {Array.<string>}
45985 * @private
45986 */
45987ol.format.GPX.LINK_SEQUENCE_ = ['text', 'type'];
45988
45989
45990/**
45991 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
45992 * @private
45993 */
45994ol.format.GPX.LINK_SERIALIZERS_ = ol.xml.makeStructureNS(
45995 ol.format.GPX.NAMESPACE_URIS_, {
45996 'text': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
45997 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
45998 });
45999
46000
46001/**
46002 * @const
46003 * @type {Object.<string, Array.<string>>}
46004 * @private
46005 */
46006ol.format.GPX.RTE_SEQUENCE_ = ol.xml.makeStructureNS(
46007 ol.format.GPX.NAMESPACE_URIS_, [
46008 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'rtept'
46009 ]);
46010
46011
46012/**
46013 * @const
46014 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
46015 * @private
46016 */
46017ol.format.GPX.RTE_SERIALIZERS_ = ol.xml.makeStructureNS(
46018 ol.format.GPX.NAMESPACE_URIS_, {
46019 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46020 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46021 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46022 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46023 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
46024 'number': ol.xml.makeChildAppender(
46025 ol.format.XSD.writeNonNegativeIntegerTextNode),
46026 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46027 'rtept': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
46028 ol.format.GPX.writeWptType_))
46029 });
46030
46031
46032/**
46033 * @const
46034 * @type {Object.<string, Array.<string>>}
46035 * @private
46036 */
46037ol.format.GPX.RTEPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(
46038 ol.format.GPX.NAMESPACE_URIS_, [
46039 'ele', 'time'
46040 ]);
46041
46042
46043/**
46044 * @const
46045 * @type {Object.<string, Array.<string>>}
46046 * @private
46047 */
46048ol.format.GPX.TRK_SEQUENCE_ = ol.xml.makeStructureNS(
46049 ol.format.GPX.NAMESPACE_URIS_, [
46050 'name', 'cmt', 'desc', 'src', 'link', 'number', 'type', 'trkseg'
46051 ]);
46052
46053
46054/**
46055 * @const
46056 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
46057 * @private
46058 */
46059ol.format.GPX.TRK_SERIALIZERS_ = ol.xml.makeStructureNS(
46060 ol.format.GPX.NAMESPACE_URIS_, {
46061 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46062 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46063 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46064 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46065 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
46066 'number': ol.xml.makeChildAppender(
46067 ol.format.XSD.writeNonNegativeIntegerTextNode),
46068 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46069 'trkseg': ol.xml.makeArraySerializer(ol.xml.makeChildAppender(
46070 ol.format.GPX.writeTrkSeg_))
46071 });
46072
46073
46074/**
46075 * @const
46076 * @type {function(*, Array.<*>, string=): (Node|undefined)}
46077 * @private
46078 */
46079ol.format.GPX.TRKSEG_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('trkpt');
46080
46081
46082/**
46083 * @const
46084 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
46085 * @private
46086 */
46087ol.format.GPX.TRKSEG_SERIALIZERS_ = ol.xml.makeStructureNS(
46088 ol.format.GPX.NAMESPACE_URIS_, {
46089 'trkpt': ol.xml.makeChildAppender(ol.format.GPX.writeWptType_)
46090 });
46091
46092
46093/**
46094 * @const
46095 * @type {Object.<string, Array.<string>>}
46096 * @private
46097 */
46098ol.format.GPX.WPT_TYPE_SEQUENCE_ = ol.xml.makeStructureNS(
46099 ol.format.GPX.NAMESPACE_URIS_, [
46100 'ele', 'time', 'magvar', 'geoidheight', 'name', 'cmt', 'desc', 'src',
46101 'link', 'sym', 'type', 'fix', 'sat', 'hdop', 'vdop', 'pdop',
46102 'ageofdgpsdata', 'dgpsid'
46103 ]);
46104
46105
46106/**
46107 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
46108 * @private
46109 */
46110ol.format.GPX.WPT_TYPE_SERIALIZERS_ = ol.xml.makeStructureNS(
46111 ol.format.GPX.NAMESPACE_URIS_, {
46112 'ele': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
46113 'time': ol.xml.makeChildAppender(ol.format.XSD.writeDateTimeTextNode),
46114 'magvar': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
46115 'geoidheight': ol.xml.makeChildAppender(
46116 ol.format.XSD.writeDecimalTextNode),
46117 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46118 'cmt': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46119 'desc': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46120 'src': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46121 'link': ol.xml.makeChildAppender(ol.format.GPX.writeLink_),
46122 'sym': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46123 'type': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46124 'fix': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
46125 'sat': ol.xml.makeChildAppender(
46126 ol.format.XSD.writeNonNegativeIntegerTextNode),
46127 'hdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
46128 'vdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
46129 'pdop': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
46130 'ageofdgpsdata': ol.xml.makeChildAppender(
46131 ol.format.XSD.writeDecimalTextNode),
46132 'dgpsid': ol.xml.makeChildAppender(
46133 ol.format.XSD.writeNonNegativeIntegerTextNode)
46134 });
46135
46136
46137/**
46138 * @const
46139 * @type {Object.<string, string>}
46140 * @private
46141 */
46142ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_ = {
46143 'Point': 'wpt',
46144 'LineString': 'rte',
46145 'MultiLineString': 'trk'
46146};
46147
46148
46149/**
46150 * @const
46151 * @param {*} value Value.
46152 * @param {Array.<*>} objectStack Object stack.
46153 * @param {string=} opt_nodeName Node name.
46154 * @return {Node|undefined} Node.
46155 * @private
46156 */
46157ol.format.GPX.GPX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
46158 var geometry = /** @type {ol.Feature} */ (value).getGeometry();
46159 if (geometry) {
46160 var nodeName = ol.format.GPX.GEOMETRY_TYPE_TO_NODENAME_[geometry.getType()];
46161 if (nodeName) {
46162 var parentNode = objectStack[objectStack.length - 1].node;
46163 return ol.xml.createElementNS(parentNode.namespaceURI, nodeName);
46164 }
46165 }
46166};
46167
46168
46169/**
46170 * @const
46171 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
46172 * @private
46173 */
46174ol.format.GPX.GPX_SERIALIZERS_ = ol.xml.makeStructureNS(
46175 ol.format.GPX.NAMESPACE_URIS_, {
46176 'rte': ol.xml.makeChildAppender(ol.format.GPX.writeRte_),
46177 'trk': ol.xml.makeChildAppender(ol.format.GPX.writeTrk_),
46178 'wpt': ol.xml.makeChildAppender(ol.format.GPX.writeWpt_)
46179 });
46180
46181
46182/**
46183 * Encode an array of features in the GPX format.
46184 * LineString geometries are output as routes (`<rte>`), and MultiLineString
46185 * as tracks (`<trk>`).
46186 *
46187 * @function
46188 * @param {Array.<ol.Feature>} features Features.
46189 * @param {olx.format.WriteOptions=} opt_options Write options.
46190 * @return {string} Result.
46191 * @api
46192 */
46193ol.format.GPX.prototype.writeFeatures;
46194
46195
46196/**
46197 * Encode an array of features in the GPX format as an XML node.
46198 * LineString geometries are output as routes (`<rte>`), and MultiLineString
46199 * as tracks (`<trk>`).
46200 *
46201 * @param {Array.<ol.Feature>} features Features.
46202 * @param {olx.format.WriteOptions=} opt_options Options.
46203 * @return {Node} Node.
46204 * @override
46205 * @api
46206 */
46207ol.format.GPX.prototype.writeFeaturesNode = function(features, opt_options) {
46208 opt_options = this.adaptOptions(opt_options);
46209 //FIXME Serialize metadata
46210 var gpx = ol.xml.createElementNS('http://www.topografix.com/GPX/1/1', 'gpx');
46211 var xmlnsUri = 'http://www.w3.org/2000/xmlns/';
46212 var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';
46213 ol.xml.setAttributeNS(gpx, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);
46214 ol.xml.setAttributeNS(gpx, xmlSchemaInstanceUri, 'xsi:schemaLocation',
46215 ol.format.GPX.SCHEMA_LOCATION_);
46216 gpx.setAttribute('version', '1.1');
46217 gpx.setAttribute('creator', 'OpenLayers');
46218
46219 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */
46220 ({node: gpx}), ol.format.GPX.GPX_SERIALIZERS_,
46221 ol.format.GPX.GPX_NODE_FACTORY_, features, [opt_options]);
46222 return gpx;
46223};
46224
46225goog.provide('ol.format.IGCZ');
46226
46227/**
46228 * IGC altitude/z. One of 'barometric', 'gps', 'none'.
46229 * @enum {string}
46230 */
46231ol.format.IGCZ = {
46232 BAROMETRIC: 'barometric',
46233 GPS: 'gps',
46234 NONE: 'none'
46235};
46236
46237goog.provide('ol.format.TextFeature');
46238
46239goog.require('ol');
46240goog.require('ol.format.Feature');
46241goog.require('ol.format.FormatType');
46242
46243
46244/**
46245 * @classdesc
46246 * Abstract base class; normally only used for creating subclasses and not
46247 * instantiated in apps.
46248 * Base class for text feature formats.
46249 *
46250 * @constructor
46251 * @abstract
46252 * @extends {ol.format.Feature}
46253 */
46254ol.format.TextFeature = function() {
46255 ol.format.Feature.call(this);
46256};
46257ol.inherits(ol.format.TextFeature, ol.format.Feature);
46258
46259
46260/**
46261 * @param {Document|Node|Object|string} source Source.
46262 * @private
46263 * @return {string} Text.
46264 */
46265ol.format.TextFeature.prototype.getText_ = function(source) {
46266 if (typeof source === 'string') {
46267 return source;
46268 } else {
46269 return '';
46270 }
46271};
46272
46273
46274/**
46275 * @inheritDoc
46276 */
46277ol.format.TextFeature.prototype.getType = function() {
46278 return ol.format.FormatType.TEXT;
46279};
46280
46281
46282/**
46283 * @inheritDoc
46284 */
46285ol.format.TextFeature.prototype.readFeature = function(source, opt_options) {
46286 return this.readFeatureFromText(
46287 this.getText_(source), this.adaptOptions(opt_options));
46288};
46289
46290
46291/**
46292 * @abstract
46293 * @param {string} text Text.
46294 * @param {olx.format.ReadOptions=} opt_options Read options.
46295 * @protected
46296 * @return {ol.Feature} Feature.
46297 */
46298ol.format.TextFeature.prototype.readFeatureFromText = function(text, opt_options) {};
46299
46300
46301/**
46302 * @inheritDoc
46303 */
46304ol.format.TextFeature.prototype.readFeatures = function(source, opt_options) {
46305 return this.readFeaturesFromText(
46306 this.getText_(source), this.adaptOptions(opt_options));
46307};
46308
46309
46310/**
46311 * @abstract
46312 * @param {string} text Text.
46313 * @param {olx.format.ReadOptions=} opt_options Read options.
46314 * @protected
46315 * @return {Array.<ol.Feature>} Features.
46316 */
46317ol.format.TextFeature.prototype.readFeaturesFromText = function(text, opt_options) {};
46318
46319
46320/**
46321 * @inheritDoc
46322 */
46323ol.format.TextFeature.prototype.readGeometry = function(source, opt_options) {
46324 return this.readGeometryFromText(
46325 this.getText_(source), this.adaptOptions(opt_options));
46326};
46327
46328
46329/**
46330 * @abstract
46331 * @param {string} text Text.
46332 * @param {olx.format.ReadOptions=} opt_options Read options.
46333 * @protected
46334 * @return {ol.geom.Geometry} Geometry.
46335 */
46336ol.format.TextFeature.prototype.readGeometryFromText = function(text, opt_options) {};
46337
46338
46339/**
46340 * @inheritDoc
46341 */
46342ol.format.TextFeature.prototype.readProjection = function(source) {
46343 return this.readProjectionFromText(this.getText_(source));
46344};
46345
46346
46347/**
46348 * @param {string} text Text.
46349 * @protected
46350 * @return {ol.proj.Projection} Projection.
46351 */
46352ol.format.TextFeature.prototype.readProjectionFromText = function(text) {
46353 return this.defaultDataProjection;
46354};
46355
46356
46357/**
46358 * @inheritDoc
46359 */
46360ol.format.TextFeature.prototype.writeFeature = function(feature, opt_options) {
46361 return this.writeFeatureText(feature, this.adaptOptions(opt_options));
46362};
46363
46364
46365/**
46366 * @abstract
46367 * @param {ol.Feature} feature Features.
46368 * @param {olx.format.WriteOptions=} opt_options Write options.
46369 * @protected
46370 * @return {string} Text.
46371 */
46372ol.format.TextFeature.prototype.writeFeatureText = function(feature, opt_options) {};
46373
46374
46375/**
46376 * @inheritDoc
46377 */
46378ol.format.TextFeature.prototype.writeFeatures = function(
46379 features, opt_options) {
46380 return this.writeFeaturesText(features, this.adaptOptions(opt_options));
46381};
46382
46383
46384/**
46385 * @abstract
46386 * @param {Array.<ol.Feature>} features Features.
46387 * @param {olx.format.WriteOptions=} opt_options Write options.
46388 * @protected
46389 * @return {string} Text.
46390 */
46391ol.format.TextFeature.prototype.writeFeaturesText = function(features, opt_options) {};
46392
46393
46394/**
46395 * @inheritDoc
46396 */
46397ol.format.TextFeature.prototype.writeGeometry = function(
46398 geometry, opt_options) {
46399 return this.writeGeometryText(geometry, this.adaptOptions(opt_options));
46400};
46401
46402
46403/**
46404 * @abstract
46405 * @param {ol.geom.Geometry} geometry Geometry.
46406 * @param {olx.format.WriteOptions=} opt_options Write options.
46407 * @protected
46408 * @return {string} Text.
46409 */
46410ol.format.TextFeature.prototype.writeGeometryText = function(geometry, opt_options) {};
46411
46412goog.provide('ol.format.IGC');
46413
46414goog.require('ol');
46415goog.require('ol.Feature');
46416goog.require('ol.format.Feature');
46417goog.require('ol.format.IGCZ');
46418goog.require('ol.format.TextFeature');
46419goog.require('ol.geom.GeometryLayout');
46420goog.require('ol.geom.LineString');
46421goog.require('ol.proj');
46422
46423
46424/**
46425 * @classdesc
46426 * Feature format for `*.igc` flight recording files.
46427 *
46428 * @constructor
46429 * @extends {ol.format.TextFeature}
46430 * @param {olx.format.IGCOptions=} opt_options Options.
46431 * @api
46432 */
46433ol.format.IGC = function(opt_options) {
46434
46435 var options = opt_options ? opt_options : {};
46436
46437 ol.format.TextFeature.call(this);
46438
46439 /**
46440 * @inheritDoc
46441 */
46442 this.defaultDataProjection = ol.proj.get('EPSG:4326');
46443
46444 /**
46445 * @private
46446 * @type {ol.format.IGCZ}
46447 */
46448 this.altitudeMode_ = options.altitudeMode ?
46449 options.altitudeMode : ol.format.IGCZ.NONE;
46450
46451};
46452ol.inherits(ol.format.IGC, ol.format.TextFeature);
46453
46454
46455/**
46456 * @const
46457 * @type {RegExp}
46458 * @private
46459 */
46460ol.format.IGC.B_RECORD_RE_ =
46461 /^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/;
46462
46463
46464/**
46465 * @const
46466 * @type {RegExp}
46467 * @private
46468 */
46469ol.format.IGC.H_RECORD_RE_ = /^H.([A-Z]{3}).*?:(.*)/;
46470
46471
46472/**
46473 * @const
46474 * @type {RegExp}
46475 * @private
46476 */
46477ol.format.IGC.HFDTE_RECORD_RE_ = /^HFDTE(\d{2})(\d{2})(\d{2})/;
46478
46479
46480/**
46481 * A regular expression matching the newline characters `\r\n`, `\r` and `\n`.
46482 *
46483 * @const
46484 * @type {RegExp}
46485 * @private
46486 */
46487ol.format.IGC.NEWLINE_RE_ = /\r\n|\r|\n/;
46488
46489
46490/**
46491 * Read the feature from the IGC source.
46492 *
46493 * @function
46494 * @param {Document|Node|Object|string} source Source.
46495 * @param {olx.format.ReadOptions=} opt_options Read options.
46496 * @return {ol.Feature} Feature.
46497 * @api
46498 */
46499ol.format.IGC.prototype.readFeature;
46500
46501
46502/**
46503 * @inheritDoc
46504 */
46505ol.format.IGC.prototype.readFeatureFromText = function(text, opt_options) {
46506 var altitudeMode = this.altitudeMode_;
46507 var lines = text.split(ol.format.IGC.NEWLINE_RE_);
46508 /** @type {Object.<string, string>} */
46509 var properties = {};
46510 var flatCoordinates = [];
46511 var year = 2000;
46512 var month = 0;
46513 var day = 1;
46514 var lastDateTime = -1;
46515 var i, ii;
46516 for (i = 0, ii = lines.length; i < ii; ++i) {
46517 var line = lines[i];
46518 var m;
46519 if (line.charAt(0) == 'B') {
46520 m = ol.format.IGC.B_RECORD_RE_.exec(line);
46521 if (m) {
46522 var hour = parseInt(m[1], 10);
46523 var minute = parseInt(m[2], 10);
46524 var second = parseInt(m[3], 10);
46525 var y = parseInt(m[4], 10) + parseInt(m[5], 10) / 60000;
46526 if (m[6] == 'S') {
46527 y = -y;
46528 }
46529 var x = parseInt(m[7], 10) + parseInt(m[8], 10) / 60000;
46530 if (m[9] == 'W') {
46531 x = -x;
46532 }
46533 flatCoordinates.push(x, y);
46534 if (altitudeMode != ol.format.IGCZ.NONE) {
46535 var z;
46536 if (altitudeMode == ol.format.IGCZ.GPS) {
46537 z = parseInt(m[11], 10);
46538 } else if (altitudeMode == ol.format.IGCZ.BAROMETRIC) {
46539 z = parseInt(m[12], 10);
46540 } else {
46541 z = 0;
46542 }
46543 flatCoordinates.push(z);
46544 }
46545 var dateTime = Date.UTC(year, month, day, hour, minute, second);
46546 // Detect UTC midnight wrap around.
46547 if (dateTime < lastDateTime) {
46548 dateTime = Date.UTC(year, month, day + 1, hour, minute, second);
46549 }
46550 flatCoordinates.push(dateTime / 1000);
46551 lastDateTime = dateTime;
46552 }
46553 } else if (line.charAt(0) == 'H') {
46554 m = ol.format.IGC.HFDTE_RECORD_RE_.exec(line);
46555 if (m) {
46556 day = parseInt(m[1], 10);
46557 month = parseInt(m[2], 10) - 1;
46558 year = 2000 + parseInt(m[3], 10);
46559 } else {
46560 m = ol.format.IGC.H_RECORD_RE_.exec(line);
46561 if (m) {
46562 properties[m[1]] = m[2].trim();
46563 }
46564 }
46565 }
46566 }
46567 if (flatCoordinates.length === 0) {
46568 return null;
46569 }
46570 var lineString = new ol.geom.LineString(null);
46571 var layout = altitudeMode == ol.format.IGCZ.NONE ?
46572 ol.geom.GeometryLayout.XYM : ol.geom.GeometryLayout.XYZM;
46573 lineString.setFlatCoordinates(layout, flatCoordinates);
46574 var feature = new ol.Feature(ol.format.Feature.transformWithOptions(
46575 lineString, false, opt_options));
46576 feature.setProperties(properties);
46577 return feature;
46578};
46579
46580
46581/**
46582 * Read the feature from the source. As IGC sources contain a single
46583 * feature, this will return the feature in an array.
46584 *
46585 * @function
46586 * @param {Document|Node|Object|string} source Source.
46587 * @param {olx.format.ReadOptions=} opt_options Read options.
46588 * @return {Array.<ol.Feature>} Features.
46589 * @api
46590 */
46591ol.format.IGC.prototype.readFeatures;
46592
46593
46594/**
46595 * @inheritDoc
46596 */
46597ol.format.IGC.prototype.readFeaturesFromText = function(text, opt_options) {
46598 var feature = this.readFeatureFromText(text, opt_options);
46599 if (feature) {
46600 return [feature];
46601 } else {
46602 return [];
46603 }
46604};
46605
46606
46607/**
46608 * Read the projection from the IGC source.
46609 *
46610 * @function
46611 * @param {Document|Node|Object|string} source Source.
46612 * @return {ol.proj.Projection} Projection.
46613 * @api
46614 */
46615ol.format.IGC.prototype.readProjection;
46616
46617
46618/**
46619 * Not implemented.
46620 * @inheritDoc
46621 */
46622ol.format.IGC.prototype.writeFeatureText = function(feature, opt_options) {};
46623
46624
46625/**
46626 * Not implemented.
46627 * @inheritDoc
46628 */
46629ol.format.IGC.prototype.writeFeaturesText = function(features, opt_options) {};
46630
46631
46632/**
46633 * Not implemented.
46634 * @inheritDoc
46635 */
46636ol.format.IGC.prototype.writeGeometryText = function(geometry, opt_options) {};
46637
46638
46639/**
46640 * Not implemented.
46641 * @inheritDoc
46642 */
46643ol.format.IGC.prototype.readGeometryFromText = function(text, opt_options) {};
46644
46645goog.provide('ol.style.IconAnchorUnits');
46646
46647/**
46648 * Icon anchor units. One of 'fraction', 'pixels'.
46649 * @enum {string}
46650 */
46651ol.style.IconAnchorUnits = {
46652 FRACTION: 'fraction',
46653 PIXELS: 'pixels'
46654};
46655
46656goog.provide('ol.style.IconImage');
46657
46658goog.require('ol');
46659goog.require('ol.dom');
46660goog.require('ol.events');
46661goog.require('ol.events.EventTarget');
46662goog.require('ol.events.EventType');
46663goog.require('ol.ImageState');
46664goog.require('ol.style');
46665
46666
46667/**
46668 * @constructor
46669 * @param {Image|HTMLCanvasElement} image Image.
46670 * @param {string|undefined} src Src.
46671 * @param {ol.Size} size Size.
46672 * @param {?string} crossOrigin Cross origin.
46673 * @param {ol.ImageState} imageState Image state.
46674 * @param {ol.Color} color Color.
46675 * @extends {ol.events.EventTarget}
46676 */
46677ol.style.IconImage = function(image, src, size, crossOrigin, imageState,
46678 color) {
46679
46680 ol.events.EventTarget.call(this);
46681
46682 /**
46683 * @private
46684 * @type {Image|HTMLCanvasElement}
46685 */
46686 this.hitDetectionImage_ = null;
46687
46688 /**
46689 * @private
46690 * @type {Image|HTMLCanvasElement}
46691 */
46692 this.image_ = !image ? new Image() : image;
46693
46694 if (crossOrigin !== null) {
46695 this.image_.crossOrigin = crossOrigin;
46696 }
46697
46698 /**
46699 * @private
46700 * @type {HTMLCanvasElement}
46701 */
46702 this.canvas_ = color ?
46703 /** @type {HTMLCanvasElement} */ (document.createElement('CANVAS')) :
46704 null;
46705
46706 /**
46707 * @private
46708 * @type {ol.Color}
46709 */
46710 this.color_ = color;
46711
46712 /**
46713 * @private
46714 * @type {Array.<ol.EventsKey>}
46715 */
46716 this.imageListenerKeys_ = null;
46717
46718 /**
46719 * @private
46720 * @type {ol.ImageState}
46721 */
46722 this.imageState_ = imageState;
46723
46724 /**
46725 * @private
46726 * @type {ol.Size}
46727 */
46728 this.size_ = size;
46729
46730 /**
46731 * @private
46732 * @type {string|undefined}
46733 */
46734 this.src_ = src;
46735
46736 /**
46737 * @private
46738 * @type {boolean}
46739 */
46740 this.tainting_ = false;
46741 if (this.imageState_ == ol.ImageState.LOADED) {
46742 this.determineTainting_();
46743 }
46744
46745};
46746ol.inherits(ol.style.IconImage, ol.events.EventTarget);
46747
46748
46749/**
46750 * @param {Image|HTMLCanvasElement} image Image.
46751 * @param {string} src Src.
46752 * @param {ol.Size} size Size.
46753 * @param {?string} crossOrigin Cross origin.
46754 * @param {ol.ImageState} imageState Image state.
46755 * @param {ol.Color} color Color.
46756 * @return {ol.style.IconImage} Icon image.
46757 */
46758ol.style.IconImage.get = function(image, src, size, crossOrigin, imageState,
46759 color) {
46760 var iconImageCache = ol.style.iconImageCache;
46761 var iconImage = iconImageCache.get(src, crossOrigin, color);
46762 if (!iconImage) {
46763 iconImage = new ol.style.IconImage(
46764 image, src, size, crossOrigin, imageState, color);
46765 iconImageCache.set(src, crossOrigin, color, iconImage);
46766 }
46767 return iconImage;
46768};
46769
46770
46771/**
46772 * @private
46773 */
46774ol.style.IconImage.prototype.determineTainting_ = function() {
46775 var context = ol.dom.createCanvasContext2D(1, 1);
46776 try {
46777 context.drawImage(this.image_, 0, 0);
46778 context.getImageData(0, 0, 1, 1);
46779 } catch (e) {
46780 this.tainting_ = true;
46781 }
46782};
46783
46784
46785/**
46786 * @private
46787 */
46788ol.style.IconImage.prototype.dispatchChangeEvent_ = function() {
46789 this.dispatchEvent(ol.events.EventType.CHANGE);
46790};
46791
46792
46793/**
46794 * @private
46795 */
46796ol.style.IconImage.prototype.handleImageError_ = function() {
46797 this.imageState_ = ol.ImageState.ERROR;
46798 this.unlistenImage_();
46799 this.dispatchChangeEvent_();
46800};
46801
46802
46803/**
46804 * @private
46805 */
46806ol.style.IconImage.prototype.handleImageLoad_ = function() {
46807 this.imageState_ = ol.ImageState.LOADED;
46808 if (this.size_) {
46809 this.image_.width = this.size_[0];
46810 this.image_.height = this.size_[1];
46811 }
46812 this.size_ = [this.image_.width, this.image_.height];
46813 this.unlistenImage_();
46814 this.determineTainting_();
46815 this.replaceColor_();
46816 this.dispatchChangeEvent_();
46817};
46818
46819
46820/**
46821 * @param {number} pixelRatio Pixel ratio.
46822 * @return {Image|HTMLCanvasElement} Image or Canvas element.
46823 */
46824ol.style.IconImage.prototype.getImage = function(pixelRatio) {
46825 return this.canvas_ ? this.canvas_ : this.image_;
46826};
46827
46828
46829/**
46830 * @return {ol.ImageState} Image state.
46831 */
46832ol.style.IconImage.prototype.getImageState = function() {
46833 return this.imageState_;
46834};
46835
46836
46837/**
46838 * @param {number} pixelRatio Pixel ratio.
46839 * @return {Image|HTMLCanvasElement} Image element.
46840 */
46841ol.style.IconImage.prototype.getHitDetectionImage = function(pixelRatio) {
46842 if (!this.hitDetectionImage_) {
46843 if (this.tainting_) {
46844 var width = this.size_[0];
46845 var height = this.size_[1];
46846 var context = ol.dom.createCanvasContext2D(width, height);
46847 context.fillRect(0, 0, width, height);
46848 this.hitDetectionImage_ = context.canvas;
46849 } else {
46850 this.hitDetectionImage_ = this.image_;
46851 }
46852 }
46853 return this.hitDetectionImage_;
46854};
46855
46856
46857/**
46858 * @return {ol.Size} Image size.
46859 */
46860ol.style.IconImage.prototype.getSize = function() {
46861 return this.size_;
46862};
46863
46864
46865/**
46866 * @return {string|undefined} Image src.
46867 */
46868ol.style.IconImage.prototype.getSrc = function() {
46869 return this.src_;
46870};
46871
46872
46873/**
46874 * Load not yet loaded URI.
46875 */
46876ol.style.IconImage.prototype.load = function() {
46877 if (this.imageState_ == ol.ImageState.IDLE) {
46878 this.imageState_ = ol.ImageState.LOADING;
46879 this.imageListenerKeys_ = [
46880 ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
46881 this.handleImageError_, this),
46882 ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
46883 this.handleImageLoad_, this)
46884 ];
46885 try {
46886 this.image_.src = this.src_;
46887 } catch (e) {
46888 this.handleImageError_();
46889 }
46890 }
46891};
46892
46893
46894/**
46895 * @private
46896 */
46897ol.style.IconImage.prototype.replaceColor_ = function() {
46898 if (this.tainting_ || this.color_ === null) {
46899 return;
46900 }
46901
46902 this.canvas_.width = this.image_.width;
46903 this.canvas_.height = this.image_.height;
46904
46905 var ctx = this.canvas_.getContext('2d');
46906 ctx.drawImage(this.image_, 0, 0);
46907
46908 var imgData = ctx.getImageData(0, 0, this.image_.width, this.image_.height);
46909 var data = imgData.data;
46910 var r = this.color_[0] / 255.0;
46911 var g = this.color_[1] / 255.0;
46912 var b = this.color_[2] / 255.0;
46913
46914 for (var i = 0, ii = data.length; i < ii; i += 4) {
46915 data[i] *= r;
46916 data[i + 1] *= g;
46917 data[i + 2] *= b;
46918 }
46919 ctx.putImageData(imgData, 0, 0);
46920};
46921
46922
46923/**
46924 * Discards event handlers which listen for load completion or errors.
46925 *
46926 * @private
46927 */
46928ol.style.IconImage.prototype.unlistenImage_ = function() {
46929 this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
46930 this.imageListenerKeys_ = null;
46931};
46932
46933goog.provide('ol.style.IconOrigin');
46934
46935/**
46936 * Icon origin. One of 'bottom-left', 'bottom-right', 'top-left', 'top-right'.
46937 * @enum {string}
46938 */
46939ol.style.IconOrigin = {
46940 BOTTOM_LEFT: 'bottom-left',
46941 BOTTOM_RIGHT: 'bottom-right',
46942 TOP_LEFT: 'top-left',
46943 TOP_RIGHT: 'top-right'
46944};
46945
46946goog.provide('ol.style.Icon');
46947
46948goog.require('ol');
46949goog.require('ol.ImageState');
46950goog.require('ol.asserts');
46951goog.require('ol.color');
46952goog.require('ol.events');
46953goog.require('ol.events.EventType');
46954goog.require('ol.style.IconAnchorUnits');
46955goog.require('ol.style.IconImage');
46956goog.require('ol.style.IconOrigin');
46957goog.require('ol.style.Image');
46958
46959
46960/**
46961 * @classdesc
46962 * Set icon style for vector features.
46963 *
46964 * @constructor
46965 * @param {olx.style.IconOptions=} opt_options Options.
46966 * @extends {ol.style.Image}
46967 * @api
46968 */
46969ol.style.Icon = function(opt_options) {
46970
46971 var options = opt_options || {};
46972
46973 /**
46974 * @private
46975 * @type {Array.<number>}
46976 */
46977 this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5];
46978
46979 /**
46980 * @private
46981 * @type {Array.<number>}
46982 */
46983 this.normalizedAnchor_ = null;
46984
46985 /**
46986 * @private
46987 * @type {ol.style.IconOrigin}
46988 */
46989 this.anchorOrigin_ = options.anchorOrigin !== undefined ?
46990 options.anchorOrigin : ol.style.IconOrigin.TOP_LEFT;
46991
46992 /**
46993 * @private
46994 * @type {ol.style.IconAnchorUnits}
46995 */
46996 this.anchorXUnits_ = options.anchorXUnits !== undefined ?
46997 options.anchorXUnits : ol.style.IconAnchorUnits.FRACTION;
46998
46999 /**
47000 * @private
47001 * @type {ol.style.IconAnchorUnits}
47002 */
47003 this.anchorYUnits_ = options.anchorYUnits !== undefined ?
47004 options.anchorYUnits : ol.style.IconAnchorUnits.FRACTION;
47005
47006 /**
47007 * @private
47008 * @type {?string}
47009 */
47010 this.crossOrigin_ =
47011 options.crossOrigin !== undefined ? options.crossOrigin : null;
47012
47013 /**
47014 * @type {Image|HTMLCanvasElement}
47015 */
47016 var image = options.img !== undefined ? options.img : null;
47017
47018 /**
47019 * @type {ol.Size}
47020 */
47021 var imgSize = options.imgSize !== undefined ? options.imgSize : null;
47022
47023 /**
47024 * @type {string|undefined}
47025 */
47026 var src = options.src;
47027
47028 ol.asserts.assert(!(src !== undefined && image),
47029 4); // `image` and `src` cannot be provided at the same time
47030 ol.asserts.assert(!image || (image && imgSize),
47031 5); // `imgSize` must be set when `image` is provided
47032
47033 if ((src === undefined || src.length === 0) && image) {
47034 src = image.src || ol.getUid(image).toString();
47035 }
47036 ol.asserts.assert(src !== undefined && src.length > 0,
47037 6); // A defined and non-empty `src` or `image` must be provided
47038
47039 /**
47040 * @type {ol.ImageState}
47041 */
47042 var imageState = options.src !== undefined ?
47043 ol.ImageState.IDLE : ol.ImageState.LOADED;
47044
47045 /**
47046 * @private
47047 * @type {ol.Color}
47048 */
47049 this.color_ = options.color !== undefined ? ol.color.asArray(options.color) :
47050 null;
47051
47052 /**
47053 * @private
47054 * @type {ol.style.IconImage}
47055 */
47056 this.iconImage_ = ol.style.IconImage.get(
47057 image, /** @type {string} */ (src), imgSize, this.crossOrigin_, imageState, this.color_);
47058
47059 /**
47060 * @private
47061 * @type {Array.<number>}
47062 */
47063 this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
47064
47065 /**
47066 * @private
47067 * @type {ol.style.IconOrigin}
47068 */
47069 this.offsetOrigin_ = options.offsetOrigin !== undefined ?
47070 options.offsetOrigin : ol.style.IconOrigin.TOP_LEFT;
47071
47072 /**
47073 * @private
47074 * @type {Array.<number>}
47075 */
47076 this.origin_ = null;
47077
47078 /**
47079 * @private
47080 * @type {ol.Size}
47081 */
47082 this.size_ = options.size !== undefined ? options.size : null;
47083
47084 /**
47085 * @type {number}
47086 */
47087 var opacity = options.opacity !== undefined ? options.opacity : 1;
47088
47089 /**
47090 * @type {boolean}
47091 */
47092 var rotateWithView = options.rotateWithView !== undefined ?
47093 options.rotateWithView : false;
47094
47095 /**
47096 * @type {number}
47097 */
47098 var rotation = options.rotation !== undefined ? options.rotation : 0;
47099
47100 /**
47101 * @type {number}
47102 */
47103 var scale = options.scale !== undefined ? options.scale : 1;
47104
47105 /**
47106 * @type {boolean}
47107 */
47108 var snapToPixel = options.snapToPixel !== undefined ?
47109 options.snapToPixel : true;
47110
47111 ol.style.Image.call(this, {
47112 opacity: opacity,
47113 rotation: rotation,
47114 scale: scale,
47115 snapToPixel: snapToPixel,
47116 rotateWithView: rotateWithView
47117 });
47118
47119};
47120ol.inherits(ol.style.Icon, ol.style.Image);
47121
47122
47123/**
47124 * Clones the style.
47125 * @return {ol.style.Icon} The cloned style.
47126 * @api
47127 */
47128ol.style.Icon.prototype.clone = function() {
47129 var oldImage = this.getImage(1);
47130 var newImage;
47131 if (this.iconImage_.getImageState() === ol.ImageState.LOADED) {
47132 if (oldImage.tagName.toUpperCase() === 'IMG') {
47133 newImage = /** @type {Image} */ (oldImage.cloneNode(true));
47134 } else {
47135 newImage = /** @type {HTMLCanvasElement} */ (document.createElement('canvas'));
47136 var context = newImage.getContext('2d');
47137 newImage.width = oldImage.width;
47138 newImage.height = oldImage.height;
47139 context.drawImage(oldImage, 0, 0);
47140 }
47141 }
47142 return new ol.style.Icon({
47143 anchor: this.anchor_.slice(),
47144 anchorOrigin: this.anchorOrigin_,
47145 anchorXUnits: this.anchorXUnits_,
47146 anchorYUnits: this.anchorYUnits_,
47147 crossOrigin: this.crossOrigin_,
47148 color: (this.color_ && this.color_.slice) ? this.color_.slice() : this.color_ || undefined,
47149 img: newImage ? newImage : undefined,
47150 imgSize: newImage ? this.iconImage_.getSize().slice() : undefined,
47151 src: newImage ? undefined : this.getSrc(),
47152 offset: this.offset_.slice(),
47153 offsetOrigin: this.offsetOrigin_,
47154 size: this.size_ !== null ? this.size_.slice() : undefined,
47155 opacity: this.getOpacity(),
47156 scale: this.getScale(),
47157 snapToPixel: this.getSnapToPixel(),
47158 rotation: this.getRotation(),
47159 rotateWithView: this.getRotateWithView()
47160 });
47161};
47162
47163
47164/**
47165 * @inheritDoc
47166 * @api
47167 */
47168ol.style.Icon.prototype.getAnchor = function() {
47169 if (this.normalizedAnchor_) {
47170 return this.normalizedAnchor_;
47171 }
47172 var anchor = this.anchor_;
47173 var size = this.getSize();
47174 if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION ||
47175 this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) {
47176 if (!size) {
47177 return null;
47178 }
47179 anchor = this.anchor_.slice();
47180 if (this.anchorXUnits_ == ol.style.IconAnchorUnits.FRACTION) {
47181 anchor[0] *= size[0];
47182 }
47183 if (this.anchorYUnits_ == ol.style.IconAnchorUnits.FRACTION) {
47184 anchor[1] *= size[1];
47185 }
47186 }
47187
47188 if (this.anchorOrigin_ != ol.style.IconOrigin.TOP_LEFT) {
47189 if (!size) {
47190 return null;
47191 }
47192 if (anchor === this.anchor_) {
47193 anchor = this.anchor_.slice();
47194 }
47195 if (this.anchorOrigin_ == ol.style.IconOrigin.TOP_RIGHT ||
47196 this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
47197 anchor[0] = -anchor[0] + size[0];
47198 }
47199 if (this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT ||
47200 this.anchorOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
47201 anchor[1] = -anchor[1] + size[1];
47202 }
47203 }
47204 this.normalizedAnchor_ = anchor;
47205 return this.normalizedAnchor_;
47206};
47207
47208
47209/**
47210 * Get the icon color.
47211 * @return {ol.Color} Color.
47212 * @api
47213 */
47214ol.style.Icon.prototype.getColor = function() {
47215 return this.color_;
47216};
47217
47218
47219/**
47220 * Get the image icon.
47221 * @param {number} pixelRatio Pixel ratio.
47222 * @return {Image|HTMLCanvasElement} Image or Canvas element.
47223 * @override
47224 * @api
47225 */
47226ol.style.Icon.prototype.getImage = function(pixelRatio) {
47227 return this.iconImage_.getImage(pixelRatio);
47228};
47229
47230
47231/**
47232 * @override
47233 */
47234ol.style.Icon.prototype.getImageSize = function() {
47235 return this.iconImage_.getSize();
47236};
47237
47238
47239/**
47240 * @override
47241 */
47242ol.style.Icon.prototype.getHitDetectionImageSize = function() {
47243 return this.getImageSize();
47244};
47245
47246
47247/**
47248 * @override
47249 */
47250ol.style.Icon.prototype.getImageState = function() {
47251 return this.iconImage_.getImageState();
47252};
47253
47254
47255/**
47256 * @override
47257 */
47258ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) {
47259 return this.iconImage_.getHitDetectionImage(pixelRatio);
47260};
47261
47262
47263/**
47264 * @inheritDoc
47265 * @api
47266 */
47267ol.style.Icon.prototype.getOrigin = function() {
47268 if (this.origin_) {
47269 return this.origin_;
47270 }
47271 var offset = this.offset_;
47272
47273 if (this.offsetOrigin_ != ol.style.IconOrigin.TOP_LEFT) {
47274 var size = this.getSize();
47275 var iconImageSize = this.iconImage_.getSize();
47276 if (!size || !iconImageSize) {
47277 return null;
47278 }
47279 offset = offset.slice();
47280 if (this.offsetOrigin_ == ol.style.IconOrigin.TOP_RIGHT ||
47281 this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
47282 offset[0] = iconImageSize[0] - size[0] - offset[0];
47283 }
47284 if (this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_LEFT ||
47285 this.offsetOrigin_ == ol.style.IconOrigin.BOTTOM_RIGHT) {
47286 offset[1] = iconImageSize[1] - size[1] - offset[1];
47287 }
47288 }
47289 this.origin_ = offset;
47290 return this.origin_;
47291};
47292
47293
47294/**
47295 * Get the image URL.
47296 * @return {string|undefined} Image src.
47297 * @api
47298 */
47299ol.style.Icon.prototype.getSrc = function() {
47300 return this.iconImage_.getSrc();
47301};
47302
47303
47304/**
47305 * @inheritDoc
47306 * @api
47307 */
47308ol.style.Icon.prototype.getSize = function() {
47309 return !this.size_ ? this.iconImage_.getSize() : this.size_;
47310};
47311
47312
47313/**
47314 * @override
47315 */
47316ol.style.Icon.prototype.listenImageChange = function(listener, thisArg) {
47317 return ol.events.listen(this.iconImage_, ol.events.EventType.CHANGE,
47318 listener, thisArg);
47319};
47320
47321
47322/**
47323 * Load not yet loaded URI.
47324 * When rendering a feature with an icon style, the vector renderer will
47325 * automatically call this method. However, you might want to call this
47326 * method yourself for preloading or other purposes.
47327 * @override
47328 * @api
47329 */
47330ol.style.Icon.prototype.load = function() {
47331 this.iconImage_.load();
47332};
47333
47334
47335/**
47336 * @override
47337 */
47338ol.style.Icon.prototype.unlistenImageChange = function(listener, thisArg) {
47339 ol.events.unlisten(this.iconImage_, ol.events.EventType.CHANGE,
47340 listener, thisArg);
47341};
47342
47343goog.provide('ol.style.Text');
47344
47345
47346goog.require('ol.style.Fill');
47347
47348
47349/**
47350 * @classdesc
47351 * Set text style for vector features.
47352 *
47353 * @constructor
47354 * @param {olx.style.TextOptions=} opt_options Options.
47355 * @api
47356 */
47357ol.style.Text = function(opt_options) {
47358
47359 var options = opt_options || {};
47360
47361 /**
47362 * @private
47363 * @type {string|undefined}
47364 */
47365 this.font_ = options.font;
47366
47367 /**
47368 * @private
47369 * @type {number|undefined}
47370 */
47371 this.rotation_ = options.rotation;
47372
47373 /**
47374 * @private
47375 * @type {boolean|undefined}
47376 */
47377 this.rotateWithView_ = options.rotateWithView;
47378
47379 /**
47380 * @private
47381 * @type {number|undefined}
47382 */
47383 this.scale_ = options.scale;
47384
47385 /**
47386 * @private
47387 * @type {string|undefined}
47388 */
47389 this.text_ = options.text;
47390
47391 /**
47392 * @private
47393 * @type {string|undefined}
47394 */
47395 this.textAlign_ = options.textAlign;
47396
47397 /**
47398 * @private
47399 * @type {string|undefined}
47400 */
47401 this.textBaseline_ = options.textBaseline;
47402
47403 /**
47404 * @private
47405 * @type {ol.style.Fill}
47406 */
47407 this.fill_ = options.fill !== undefined ? options.fill :
47408 new ol.style.Fill({color: ol.style.Text.DEFAULT_FILL_COLOR_});
47409
47410 /**
47411 * @private
47412 * @type {ol.style.Stroke}
47413 */
47414 this.stroke_ = options.stroke !== undefined ? options.stroke : null;
47415
47416 /**
47417 * @private
47418 * @type {number}
47419 */
47420 this.offsetX_ = options.offsetX !== undefined ? options.offsetX : 0;
47421
47422 /**
47423 * @private
47424 * @type {number}
47425 */
47426 this.offsetY_ = options.offsetY !== undefined ? options.offsetY : 0;
47427};
47428
47429
47430/**
47431 * The default fill color to use if no fill was set at construction time; a
47432 * blackish `#333`.
47433 *
47434 * @const {string}
47435 * @private
47436 */
47437ol.style.Text.DEFAULT_FILL_COLOR_ = '#333';
47438
47439
47440/**
47441 * Clones the style.
47442 * @return {ol.style.Text} The cloned style.
47443 * @api
47444 */
47445ol.style.Text.prototype.clone = function() {
47446 return new ol.style.Text({
47447 font: this.getFont(),
47448 rotation: this.getRotation(),
47449 rotateWithView: this.getRotateWithView(),
47450 scale: this.getScale(),
47451 text: this.getText(),
47452 textAlign: this.getTextAlign(),
47453 textBaseline: this.getTextBaseline(),
47454 fill: this.getFill() ? this.getFill().clone() : undefined,
47455 stroke: this.getStroke() ? this.getStroke().clone() : undefined,
47456 offsetX: this.getOffsetX(),
47457 offsetY: this.getOffsetY()
47458 });
47459};
47460
47461
47462/**
47463 * Get the font name.
47464 * @return {string|undefined} Font.
47465 * @api
47466 */
47467ol.style.Text.prototype.getFont = function() {
47468 return this.font_;
47469};
47470
47471
47472/**
47473 * Get the x-offset for the text.
47474 * @return {number} Horizontal text offset.
47475 * @api
47476 */
47477ol.style.Text.prototype.getOffsetX = function() {
47478 return this.offsetX_;
47479};
47480
47481
47482/**
47483 * Get the y-offset for the text.
47484 * @return {number} Vertical text offset.
47485 * @api
47486 */
47487ol.style.Text.prototype.getOffsetY = function() {
47488 return this.offsetY_;
47489};
47490
47491
47492/**
47493 * Get the fill style for the text.
47494 * @return {ol.style.Fill} Fill style.
47495 * @api
47496 */
47497ol.style.Text.prototype.getFill = function() {
47498 return this.fill_;
47499};
47500
47501
47502/**
47503 * Determine whether the text rotates with the map.
47504 * @return {boolean|undefined} Rotate with map.
47505 * @api
47506 */
47507ol.style.Text.prototype.getRotateWithView = function() {
47508 return this.rotateWithView_;
47509};
47510
47511
47512/**
47513 * Get the text rotation.
47514 * @return {number|undefined} Rotation.
47515 * @api
47516 */
47517ol.style.Text.prototype.getRotation = function() {
47518 return this.rotation_;
47519};
47520
47521
47522/**
47523 * Get the text scale.
47524 * @return {number|undefined} Scale.
47525 * @api
47526 */
47527ol.style.Text.prototype.getScale = function() {
47528 return this.scale_;
47529};
47530
47531
47532/**
47533 * Get the stroke style for the text.
47534 * @return {ol.style.Stroke} Stroke style.
47535 * @api
47536 */
47537ol.style.Text.prototype.getStroke = function() {
47538 return this.stroke_;
47539};
47540
47541
47542/**
47543 * Get the text to be rendered.
47544 * @return {string|undefined} Text.
47545 * @api
47546 */
47547ol.style.Text.prototype.getText = function() {
47548 return this.text_;
47549};
47550
47551
47552/**
47553 * Get the text alignment.
47554 * @return {string|undefined} Text align.
47555 * @api
47556 */
47557ol.style.Text.prototype.getTextAlign = function() {
47558 return this.textAlign_;
47559};
47560
47561
47562/**
47563 * Get the text baseline.
47564 * @return {string|undefined} Text baseline.
47565 * @api
47566 */
47567ol.style.Text.prototype.getTextBaseline = function() {
47568 return this.textBaseline_;
47569};
47570
47571
47572/**
47573 * Set the font.
47574 *
47575 * @param {string|undefined} font Font.
47576 * @api
47577 */
47578ol.style.Text.prototype.setFont = function(font) {
47579 this.font_ = font;
47580};
47581
47582
47583/**
47584 * Set the x offset.
47585 *
47586 * @param {number} offsetX Horizontal text offset.
47587 * @api
47588 */
47589ol.style.Text.prototype.setOffsetX = function(offsetX) {
47590 this.offsetX_ = offsetX;
47591};
47592
47593
47594/**
47595 * Set the y offset.
47596 *
47597 * @param {number} offsetY Vertical text offset.
47598 * @api
47599 */
47600ol.style.Text.prototype.setOffsetY = function(offsetY) {
47601 this.offsetY_ = offsetY;
47602};
47603
47604
47605/**
47606 * Set the fill.
47607 *
47608 * @param {ol.style.Fill} fill Fill style.
47609 * @api
47610 */
47611ol.style.Text.prototype.setFill = function(fill) {
47612 this.fill_ = fill;
47613};
47614
47615
47616/**
47617 * Set the rotation.
47618 *
47619 * @param {number|undefined} rotation Rotation.
47620 * @api
47621 */
47622ol.style.Text.prototype.setRotation = function(rotation) {
47623 this.rotation_ = rotation;
47624};
47625
47626
47627/**
47628 * Set the scale.
47629 *
47630 * @param {number|undefined} scale Scale.
47631 * @api
47632 */
47633ol.style.Text.prototype.setScale = function(scale) {
47634 this.scale_ = scale;
47635};
47636
47637
47638/**
47639 * Set the stroke.
47640 *
47641 * @param {ol.style.Stroke} stroke Stroke style.
47642 * @api
47643 */
47644ol.style.Text.prototype.setStroke = function(stroke) {
47645 this.stroke_ = stroke;
47646};
47647
47648
47649/**
47650 * Set the text.
47651 *
47652 * @param {string|undefined} text Text.
47653 * @api
47654 */
47655ol.style.Text.prototype.setText = function(text) {
47656 this.text_ = text;
47657};
47658
47659
47660/**
47661 * Set the text alignment.
47662 *
47663 * @param {string|undefined} textAlign Text align.
47664 * @api
47665 */
47666ol.style.Text.prototype.setTextAlign = function(textAlign) {
47667 this.textAlign_ = textAlign;
47668};
47669
47670
47671/**
47672 * Set the text baseline.
47673 *
47674 * @param {string|undefined} textBaseline Text baseline.
47675 * @api
47676 */
47677ol.style.Text.prototype.setTextBaseline = function(textBaseline) {
47678 this.textBaseline_ = textBaseline;
47679};
47680
47681// FIXME http://earth.google.com/kml/1.0 namespace?
47682// FIXME why does node.getAttribute return an unknown type?
47683// FIXME serialize arbitrary feature properties
47684// FIXME don't parse style if extractStyles is false
47685
47686goog.provide('ol.format.KML');
47687
47688goog.require('ol');
47689goog.require('ol.Feature');
47690goog.require('ol.array');
47691goog.require('ol.asserts');
47692goog.require('ol.color');
47693goog.require('ol.format.Feature');
47694goog.require('ol.format.XMLFeature');
47695goog.require('ol.format.XSD');
47696goog.require('ol.geom.GeometryCollection');
47697goog.require('ol.geom.GeometryLayout');
47698goog.require('ol.geom.GeometryType');
47699goog.require('ol.geom.LineString');
47700goog.require('ol.geom.MultiLineString');
47701goog.require('ol.geom.MultiPoint');
47702goog.require('ol.geom.MultiPolygon');
47703goog.require('ol.geom.Point');
47704goog.require('ol.geom.Polygon');
47705goog.require('ol.math');
47706goog.require('ol.proj');
47707goog.require('ol.style.Fill');
47708goog.require('ol.style.Icon');
47709goog.require('ol.style.IconAnchorUnits');
47710goog.require('ol.style.IconOrigin');
47711goog.require('ol.style.Stroke');
47712goog.require('ol.style.Style');
47713goog.require('ol.style.Text');
47714goog.require('ol.xml');
47715
47716
47717/**
47718 * @classdesc
47719 * Feature format for reading and writing data in the KML format.
47720 *
47721 * Note that the KML format uses the URL() constructor. Older browsers such as IE
47722 * which do not support this will need a URL polyfill to be loaded before use.
47723 *
47724 * @constructor
47725 * @extends {ol.format.XMLFeature}
47726 * @param {olx.format.KMLOptions=} opt_options Options.
47727 * @api
47728 */
47729ol.format.KML = function(opt_options) {
47730
47731 var options = opt_options ? opt_options : {};
47732
47733 ol.format.XMLFeature.call(this);
47734
47735 if (!ol.format.KML.DEFAULT_STYLE_ARRAY_) {
47736 ol.format.KML.createStyleDefaults_();
47737 }
47738
47739 /**
47740 * @inheritDoc
47741 */
47742 this.defaultDataProjection = ol.proj.get('EPSG:4326');
47743
47744 /**
47745 * @private
47746 * @type {Array.<ol.style.Style>}
47747 */
47748 this.defaultStyle_ = options.defaultStyle ?
47749 options.defaultStyle : ol.format.KML.DEFAULT_STYLE_ARRAY_;
47750
47751 /**
47752 * @private
47753 * @type {boolean}
47754 */
47755 this.extractStyles_ = options.extractStyles !== undefined ?
47756 options.extractStyles : true;
47757
47758 /**
47759 * @private
47760 * @type {boolean}
47761 */
47762 this.writeStyles_ = options.writeStyles !== undefined ?
47763 options.writeStyles : true;
47764
47765 /**
47766 * @private
47767 * @type {Object.<string, (Array.<ol.style.Style>|string)>}
47768 */
47769 this.sharedStyles_ = {};
47770
47771 /**
47772 * @private
47773 * @type {boolean}
47774 */
47775 this.showPointNames_ = options.showPointNames !== undefined ?
47776 options.showPointNames : true;
47777
47778};
47779ol.inherits(ol.format.KML, ol.format.XMLFeature);
47780
47781
47782/**
47783 * @const
47784 * @type {Array.<string>}
47785 * @private
47786 */
47787ol.format.KML.GX_NAMESPACE_URIS_ = [
47788 'http://www.google.com/kml/ext/2.2'
47789];
47790
47791
47792/**
47793 * @const
47794 * @type {Array.<string>}
47795 * @private
47796 */
47797ol.format.KML.NAMESPACE_URIS_ = [
47798 null,
47799 'http://earth.google.com/kml/2.0',
47800 'http://earth.google.com/kml/2.1',
47801 'http://earth.google.com/kml/2.2',
47802 'http://www.opengis.net/kml/2.2'
47803];
47804
47805
47806/**
47807 * @const
47808 * @type {string}
47809 * @private
47810 */
47811ol.format.KML.SCHEMA_LOCATION_ = 'http://www.opengis.net/kml/2.2 ' +
47812 'https://developers.google.com/kml/schema/kml22gx.xsd';
47813
47814
47815/**
47816 * @return {Array.<ol.style.Style>} Default style.
47817 * @private
47818 */
47819ol.format.KML.createStyleDefaults_ = function() {
47820 /**
47821 * @const
47822 * @type {ol.Color}
47823 * @private
47824 */
47825 ol.format.KML.DEFAULT_COLOR_ = [255, 255, 255, 1];
47826
47827 /**
47828 * @const
47829 * @type {ol.style.Fill}
47830 * @private
47831 */
47832 ol.format.KML.DEFAULT_FILL_STYLE_ = new ol.style.Fill({
47833 color: ol.format.KML.DEFAULT_COLOR_
47834 });
47835
47836 /**
47837 * @const
47838 * @type {ol.Size}
47839 * @private
47840 */
47841 ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_ = [20, 2]; // FIXME maybe [8, 32] ?
47842
47843 /**
47844 * @const
47845 * @type {ol.style.IconAnchorUnits}
47846 * @private
47847 */
47848 ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_ =
47849 ol.style.IconAnchorUnits.PIXELS;
47850
47851 /**
47852 * @const
47853 * @type {ol.style.IconAnchorUnits}
47854 * @private
47855 */
47856 ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_ =
47857 ol.style.IconAnchorUnits.PIXELS;
47858
47859 /**
47860 * @const
47861 * @type {ol.Size}
47862 * @private
47863 */
47864 ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_ = [64, 64];
47865
47866 /**
47867 * @const
47868 * @type {string}
47869 * @private
47870 */
47871 ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_ =
47872 'https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png';
47873
47874 /**
47875 * @const
47876 * @type {number}
47877 * @private
47878 */
47879 ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_ = 0.5;
47880
47881 /**
47882 * @const
47883 * @type {ol.style.Image}
47884 * @private
47885 */
47886 ol.format.KML.DEFAULT_IMAGE_STYLE_ = new ol.style.Icon({
47887 anchor: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_,
47888 anchorOrigin: ol.style.IconOrigin.BOTTOM_LEFT,
47889 anchorXUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_,
47890 anchorYUnits: ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_,
47891 crossOrigin: 'anonymous',
47892 rotation: 0,
47893 scale: ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_,
47894 size: ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_,
47895 src: ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_
47896 });
47897
47898 /**
47899 * @const
47900 * @type {string}
47901 * @private
47902 */
47903 ol.format.KML.DEFAULT_NO_IMAGE_STYLE_ = 'NO_IMAGE';
47904
47905 /**
47906 * @const
47907 * @type {ol.style.Stroke}
47908 * @private
47909 */
47910 ol.format.KML.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({
47911 color: ol.format.KML.DEFAULT_COLOR_,
47912 width: 1
47913 });
47914
47915 /**
47916 * @const
47917 * @type {ol.style.Stroke}
47918 * @private
47919 */
47920 ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_ = new ol.style.Stroke({
47921 color: [51, 51, 51, 1],
47922 width: 2
47923 });
47924
47925 /**
47926 * @const
47927 * @type {ol.style.Text}
47928 * @private
47929 */
47930 ol.format.KML.DEFAULT_TEXT_STYLE_ = new ol.style.Text({
47931 font: 'bold 16px Helvetica',
47932 fill: ol.format.KML.DEFAULT_FILL_STYLE_,
47933 stroke: ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_,
47934 scale: 0.8
47935 });
47936
47937 /**
47938 * @const
47939 * @type {ol.style.Style}
47940 * @private
47941 */
47942 ol.format.KML.DEFAULT_STYLE_ = new ol.style.Style({
47943 fill: ol.format.KML.DEFAULT_FILL_STYLE_,
47944 image: ol.format.KML.DEFAULT_IMAGE_STYLE_,
47945 text: ol.format.KML.DEFAULT_TEXT_STYLE_,
47946 stroke: ol.format.KML.DEFAULT_STROKE_STYLE_,
47947 zIndex: 0
47948 });
47949
47950 /**
47951 * @const
47952 * @type {Array.<ol.style.Style>}
47953 * @private
47954 */
47955 ol.format.KML.DEFAULT_STYLE_ARRAY_ = [ol.format.KML.DEFAULT_STYLE_];
47956
47957 return ol.format.KML.DEFAULT_STYLE_ARRAY_;
47958};
47959
47960
47961/**
47962 * @const
47963 * @type {Object.<string, ol.style.IconAnchorUnits>}
47964 * @private
47965 */
47966ol.format.KML.ICON_ANCHOR_UNITS_MAP_ = {
47967 'fraction': ol.style.IconAnchorUnits.FRACTION,
47968 'pixels': ol.style.IconAnchorUnits.PIXELS,
47969 'insetPixels': ol.style.IconAnchorUnits.PIXELS
47970};
47971
47972
47973/**
47974 * @param {ol.style.Style|undefined} foundStyle Style.
47975 * @param {string} name Name.
47976 * @return {ol.style.Style} style Style.
47977 * @private
47978 */
47979ol.format.KML.createNameStyleFunction_ = function(foundStyle, name) {
47980 var textStyle = null;
47981 var textOffset = [0, 0];
47982 var textAlign = 'start';
47983 if (foundStyle.getImage()) {
47984 var imageSize = foundStyle.getImage().getImageSize();
47985 if (imageSize === null) {
47986 imageSize = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_;
47987 }
47988 if (imageSize.length == 2) {
47989 var imageScale = foundStyle.getImage().getScale();
47990 // Offset the label to be centered to the right of the icon, if there is
47991 // one.
47992 textOffset[0] = imageScale * imageSize[0] / 2;
47993 textOffset[1] = -imageScale * imageSize[1] / 2;
47994 textAlign = 'left';
47995 }
47996 }
47997 if (foundStyle.getText() !== null) {
47998 // clone the text style, customizing it with name, alignments and offset.
47999 // Note that kml does not support many text options that OpenLayers does (rotation, textBaseline).
48000 var foundText = foundStyle.getText();
48001 textStyle = foundText.clone();
48002 textStyle.setFont(foundText.getFont() || ol.format.KML.DEFAULT_TEXT_STYLE_.getFont());
48003 textStyle.setScale(foundText.getScale() || ol.format.KML.DEFAULT_TEXT_STYLE_.getScale());
48004 textStyle.setFill(foundText.getFill() || ol.format.KML.DEFAULT_TEXT_STYLE_.getFill());
48005 textStyle.setStroke(foundText.getStroke() || ol.format.KML.DEFAULT_TEXT_STROKE_STYLE_);
48006 } else {
48007 textStyle = ol.format.KML.DEFAULT_TEXT_STYLE_.clone();
48008 }
48009 textStyle.setText(name);
48010 textStyle.setOffsetX(textOffset[0]);
48011 textStyle.setOffsetY(textOffset[1]);
48012 textStyle.setTextAlign(textAlign);
48013
48014 var nameStyle = new ol.style.Style({
48015 text: textStyle
48016 });
48017 return nameStyle;
48018};
48019
48020
48021/**
48022 * @param {Array.<ol.style.Style>|undefined} style Style.
48023 * @param {string} styleUrl Style URL.
48024 * @param {Array.<ol.style.Style>} defaultStyle Default style.
48025 * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles Shared
48026 * styles.
48027 * @param {boolean|undefined} showPointNames true to show names for point
48028 * placemarks.
48029 * @return {ol.FeatureStyleFunction} Feature style function.
48030 * @private
48031 */
48032ol.format.KML.createFeatureStyleFunction_ = function(style, styleUrl,
48033 defaultStyle, sharedStyles, showPointNames) {
48034
48035 return (
48036 /**
48037 * @param {number} resolution Resolution.
48038 * @return {Array.<ol.style.Style>} Style.
48039 * @this {ol.Feature}
48040 */
48041 function(resolution) {
48042 var drawName = showPointNames;
48043 /** @type {ol.style.Style|undefined} */
48044 var nameStyle;
48045 var name = '';
48046 if (drawName) {
48047 if (this.getGeometry()) {
48048 drawName = (this.getGeometry().getType() ===
48049 ol.geom.GeometryType.POINT);
48050 }
48051 }
48052
48053 if (drawName) {
48054 name = /** @type {string} */ (this.get('name'));
48055 drawName = drawName && name;
48056 }
48057
48058 if (style) {
48059 if (drawName) {
48060 nameStyle = ol.format.KML.createNameStyleFunction_(style[0],
48061 name);
48062 return style.concat(nameStyle);
48063 }
48064 return style;
48065 }
48066 if (styleUrl) {
48067 var foundStyle = ol.format.KML.findStyle_(styleUrl, defaultStyle,
48068 sharedStyles);
48069 if (drawName) {
48070 nameStyle = ol.format.KML.createNameStyleFunction_(foundStyle[0],
48071 name);
48072 return foundStyle.concat(nameStyle);
48073 }
48074 return foundStyle;
48075 }
48076 if (drawName) {
48077 nameStyle = ol.format.KML.createNameStyleFunction_(defaultStyle[0],
48078 name);
48079 return defaultStyle.concat(nameStyle);
48080 }
48081 return defaultStyle;
48082 });
48083};
48084
48085
48086/**
48087 * @param {Array.<ol.style.Style>|string|undefined} styleValue Style value.
48088 * @param {Array.<ol.style.Style>} defaultStyle Default style.
48089 * @param {Object.<string, (Array.<ol.style.Style>|string)>} sharedStyles
48090 * Shared styles.
48091 * @return {Array.<ol.style.Style>} Style.
48092 * @private
48093 */
48094ol.format.KML.findStyle_ = function(styleValue, defaultStyle, sharedStyles) {
48095 if (Array.isArray(styleValue)) {
48096 return styleValue;
48097 } else if (typeof styleValue === 'string') {
48098 // KML files in the wild occasionally forget the leading `#` on styleUrls
48099 // defined in the same document. Add a leading `#` if it enables to find
48100 // a style.
48101 if (!(styleValue in sharedStyles) && ('#' + styleValue in sharedStyles)) {
48102 styleValue = '#' + styleValue;
48103 }
48104 return ol.format.KML.findStyle_(
48105 sharedStyles[styleValue], defaultStyle, sharedStyles);
48106 } else {
48107 return defaultStyle;
48108 }
48109};
48110
48111
48112/**
48113 * @param {Node} node Node.
48114 * @private
48115 * @return {ol.Color|undefined} Color.
48116 */
48117ol.format.KML.readColor_ = function(node) {
48118 var s = ol.xml.getAllTextContent(node, false);
48119 // The KML specification states that colors should not include a leading `#`
48120 // but we tolerate them.
48121 var m = /^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(s);
48122 if (m) {
48123 var hexColor = m[1];
48124 return [
48125 parseInt(hexColor.substr(6, 2), 16),
48126 parseInt(hexColor.substr(4, 2), 16),
48127 parseInt(hexColor.substr(2, 2), 16),
48128 parseInt(hexColor.substr(0, 2), 16) / 255
48129 ];
48130
48131 } else {
48132 return undefined;
48133 }
48134};
48135
48136
48137/**
48138 * @param {Node} node Node.
48139 * @private
48140 * @return {Array.<number>|undefined} Flat coordinates.
48141 */
48142ol.format.KML.readFlatCoordinates_ = function(node) {
48143 var s = ol.xml.getAllTextContent(node, false);
48144 var flatCoordinates = [];
48145 // The KML specification states that coordinate tuples should not include
48146 // spaces, but we tolerate them.
48147 var re =
48148 /^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s*,\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?))?\s*/i;
48149 var m;
48150 while ((m = re.exec(s))) {
48151 var x = parseFloat(m[1]);
48152 var y = parseFloat(m[2]);
48153 var z = m[3] ? parseFloat(m[3]) : 0;
48154 flatCoordinates.push(x, y, z);
48155 s = s.substr(m[0].length);
48156 }
48157 if (s !== '') {
48158 return undefined;
48159 }
48160 return flatCoordinates;
48161};
48162
48163
48164/**
48165 * @param {Node} node Node.
48166 * @private
48167 * @return {string} URI.
48168 */
48169ol.format.KML.readURI_ = function(node) {
48170 var s = ol.xml.getAllTextContent(node, false).trim();
48171 if (node.baseURI && node.baseURI !== 'about:blank') {
48172 var url = new URL(s, node.baseURI);
48173 return url.href;
48174 } else {
48175 return s;
48176 }
48177};
48178
48179
48180/**
48181 * @param {Node} node Node.
48182 * @private
48183 * @return {ol.KMLVec2_} Vec2.
48184 */
48185ol.format.KML.readVec2_ = function(node) {
48186 var xunits = node.getAttribute('xunits');
48187 var yunits = node.getAttribute('yunits');
48188 var origin;
48189 if (xunits !== 'insetPixels') {
48190 if (yunits !== 'insetPixels') {
48191 origin = ol.style.IconOrigin.BOTTOM_LEFT;
48192 } else {
48193 origin = ol.style.IconOrigin.TOP_LEFT;
48194 }
48195 } else {
48196 if (yunits !== 'insetPixels') {
48197 origin = ol.style.IconOrigin.BOTTOM_RIGHT;
48198 } else {
48199 origin = ol.style.IconOrigin.TOP_RIGHT;
48200 }
48201 }
48202 return {
48203 x: parseFloat(node.getAttribute('x')),
48204 xunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[xunits],
48205 y: parseFloat(node.getAttribute('y')),
48206 yunits: ol.format.KML.ICON_ANCHOR_UNITS_MAP_[yunits],
48207 origin: origin
48208 };
48209};
48210
48211
48212/**
48213 * @param {Node} node Node.
48214 * @private
48215 * @return {number|undefined} Scale.
48216 */
48217ol.format.KML.readScale_ = function(node) {
48218 return ol.format.XSD.readDecimal(node);
48219};
48220
48221
48222/**
48223 * @param {Node} node Node.
48224 * @param {Array.<*>} objectStack Object stack.
48225 * @private
48226 * @return {Array.<ol.style.Style>|string|undefined} StyleMap.
48227 */
48228ol.format.KML.readStyleMapValue_ = function(node, objectStack) {
48229 return ol.xml.pushParseAndPop(undefined,
48230 ol.format.KML.STYLE_MAP_PARSERS_, node, objectStack);
48231};
48232/**
48233 * @param {Node} node Node.
48234 * @param {Array.<*>} objectStack Object stack.
48235 * @private
48236 */
48237ol.format.KML.IconStyleParser_ = function(node, objectStack) {
48238 // FIXME refreshMode
48239 // FIXME refreshInterval
48240 // FIXME viewRefreshTime
48241 // FIXME viewBoundScale
48242 // FIXME viewFormat
48243 // FIXME httpQuery
48244 var object = ol.xml.pushParseAndPop(
48245 {}, ol.format.KML.ICON_STYLE_PARSERS_, node, objectStack);
48246 if (!object) {
48247 return;
48248 }
48249 var styleObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);
48250 var IconObject = 'Icon' in object ? object['Icon'] : {};
48251 var drawIcon = (!('Icon' in object) || Object.keys(IconObject).length > 0);
48252 var src;
48253 var href = /** @type {string|undefined} */
48254 (IconObject['href']);
48255 if (href) {
48256 src = href;
48257 } else if (drawIcon) {
48258 src = ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_;
48259 }
48260 var anchor, anchorXUnits, anchorYUnits;
48261 var anchorOrigin = ol.style.IconOrigin.BOTTOM_LEFT;
48262 var hotSpot = /** @type {ol.KMLVec2_|undefined} */
48263 (object['hotSpot']);
48264 if (hotSpot) {
48265 anchor = [hotSpot.x, hotSpot.y];
48266 anchorXUnits = hotSpot.xunits;
48267 anchorYUnits = hotSpot.yunits;
48268 anchorOrigin = hotSpot.origin;
48269 } else if (src === ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {
48270 anchor = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_;
48271 anchorXUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_X_UNITS_;
48272 anchorYUnits = ol.format.KML.DEFAULT_IMAGE_STYLE_ANCHOR_Y_UNITS_;
48273 } else if (/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(src)) {
48274 anchor = [0.5, 0];
48275 anchorXUnits = ol.style.IconAnchorUnits.FRACTION;
48276 anchorYUnits = ol.style.IconAnchorUnits.FRACTION;
48277 }
48278
48279 var offset;
48280 var x = /** @type {number|undefined} */
48281 (IconObject['x']);
48282 var y = /** @type {number|undefined} */
48283 (IconObject['y']);
48284 if (x !== undefined && y !== undefined) {
48285 offset = [x, y];
48286 }
48287
48288 var size;
48289 var w = /** @type {number|undefined} */
48290 (IconObject['w']);
48291 var h = /** @type {number|undefined} */
48292 (IconObject['h']);
48293 if (w !== undefined && h !== undefined) {
48294 size = [w, h];
48295 }
48296
48297 var rotation;
48298 var heading = /** @type {number} */
48299 (object['heading']);
48300 if (heading !== undefined) {
48301 rotation = ol.math.toRadians(heading);
48302 }
48303
48304 var scale = /** @type {number|undefined} */
48305 (object['scale']);
48306
48307 if (drawIcon) {
48308 if (src == ol.format.KML.DEFAULT_IMAGE_STYLE_SRC_) {
48309 size = ol.format.KML.DEFAULT_IMAGE_STYLE_SIZE_;
48310 if (scale === undefined) {
48311 scale = ol.format.KML.DEFAULT_IMAGE_SCALE_MULTIPLIER_;
48312 }
48313 }
48314
48315 var imageStyle = new ol.style.Icon({
48316 anchor: anchor,
48317 anchorOrigin: anchorOrigin,
48318 anchorXUnits: anchorXUnits,
48319 anchorYUnits: anchorYUnits,
48320 crossOrigin: 'anonymous', // FIXME should this be configurable?
48321 offset: offset,
48322 offsetOrigin: ol.style.IconOrigin.BOTTOM_LEFT,
48323 rotation: rotation,
48324 scale: scale,
48325 size: size,
48326 src: src
48327 });
48328 styleObject['imageStyle'] = imageStyle;
48329 } else {
48330 // handle the case when we explicitly want to draw no icon.
48331 styleObject['imageStyle'] = ol.format.KML.DEFAULT_NO_IMAGE_STYLE_;
48332 }
48333};
48334
48335
48336/**
48337 * @param {Node} node Node.
48338 * @param {Array.<*>} objectStack Object stack.
48339 * @private
48340 */
48341ol.format.KML.LabelStyleParser_ = function(node, objectStack) {
48342 // FIXME colorMode
48343 var object = ol.xml.pushParseAndPop(
48344 {}, ol.format.KML.LABEL_STYLE_PARSERS_, node, objectStack);
48345 if (!object) {
48346 return;
48347 }
48348 var styleObject = objectStack[objectStack.length - 1];
48349 var textStyle = new ol.style.Text({
48350 fill: new ol.style.Fill({
48351 color: /** @type {ol.Color} */
48352 ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)
48353 }),
48354 scale: /** @type {number|undefined} */
48355 (object['scale'])
48356 });
48357 styleObject['textStyle'] = textStyle;
48358};
48359
48360
48361/**
48362 * @param {Node} node Node.
48363 * @param {Array.<*>} objectStack Object stack.
48364 * @private
48365 */
48366ol.format.KML.LineStyleParser_ = function(node, objectStack) {
48367 // FIXME colorMode
48368 // FIXME gx:outerColor
48369 // FIXME gx:outerWidth
48370 // FIXME gx:physicalWidth
48371 // FIXME gx:labelVisibility
48372 var object = ol.xml.pushParseAndPop(
48373 {}, ol.format.KML.LINE_STYLE_PARSERS_, node, objectStack);
48374 if (!object) {
48375 return;
48376 }
48377 var styleObject = objectStack[objectStack.length - 1];
48378 var strokeStyle = new ol.style.Stroke({
48379 color: /** @type {ol.Color} */
48380 ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_),
48381 width: /** @type {number} */ ('width' in object ? object['width'] : 1)
48382 });
48383 styleObject['strokeStyle'] = strokeStyle;
48384};
48385
48386
48387/**
48388 * @param {Node} node Node.
48389 * @param {Array.<*>} objectStack Object stack.
48390 * @private
48391 */
48392ol.format.KML.PolyStyleParser_ = function(node, objectStack) {
48393 // FIXME colorMode
48394 var object = ol.xml.pushParseAndPop(
48395 {}, ol.format.KML.POLY_STYLE_PARSERS_, node, objectStack);
48396 if (!object) {
48397 return;
48398 }
48399 var styleObject = objectStack[objectStack.length - 1];
48400 var fillStyle = new ol.style.Fill({
48401 color: /** @type {ol.Color} */
48402 ('color' in object ? object['color'] : ol.format.KML.DEFAULT_COLOR_)
48403 });
48404 styleObject['fillStyle'] = fillStyle;
48405 var fill = /** @type {boolean|undefined} */ (object['fill']);
48406 if (fill !== undefined) {
48407 styleObject['fill'] = fill;
48408 }
48409 var outline =
48410 /** @type {boolean|undefined} */ (object['outline']);
48411 if (outline !== undefined) {
48412 styleObject['outline'] = outline;
48413 }
48414};
48415
48416
48417/**
48418 * @param {Node} node Node.
48419 * @param {Array.<*>} objectStack Object stack.
48420 * @private
48421 * @return {Array.<number>} LinearRing flat coordinates.
48422 */
48423ol.format.KML.readFlatLinearRing_ = function(node, objectStack) {
48424 return ol.xml.pushParseAndPop(null,
48425 ol.format.KML.FLAT_LINEAR_RING_PARSERS_, node, objectStack);
48426};
48427
48428
48429/**
48430 * @param {Node} node Node.
48431 * @param {Array.<*>} objectStack Object stack.
48432 * @private
48433 */
48434ol.format.KML.gxCoordParser_ = function(node, objectStack) {
48435 var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */
48436 (objectStack[objectStack.length - 1]);
48437 var flatCoordinates = gxTrackObject.flatCoordinates;
48438 var s = ol.xml.getAllTextContent(node, false);
48439 var re =
48440 /^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i;
48441 var m = re.exec(s);
48442 if (m) {
48443 var x = parseFloat(m[1]);
48444 var y = parseFloat(m[2]);
48445 var z = parseFloat(m[3]);
48446 flatCoordinates.push(x, y, z, 0);
48447 } else {
48448 flatCoordinates.push(0, 0, 0, 0);
48449 }
48450};
48451
48452
48453/**
48454 * @param {Node} node Node.
48455 * @param {Array.<*>} objectStack Object stack.
48456 * @private
48457 * @return {ol.geom.MultiLineString|undefined} MultiLineString.
48458 */
48459ol.format.KML.readGxMultiTrack_ = function(node, objectStack) {
48460 var lineStrings = ol.xml.pushParseAndPop([],
48461 ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_, node, objectStack);
48462 if (!lineStrings) {
48463 return undefined;
48464 }
48465 var multiLineString = new ol.geom.MultiLineString(null);
48466 multiLineString.setLineStrings(lineStrings);
48467 return multiLineString;
48468};
48469
48470
48471/**
48472 * @param {Node} node Node.
48473 * @param {Array.<*>} objectStack Object stack.
48474 * @private
48475 * @return {ol.geom.LineString|undefined} LineString.
48476 */
48477ol.format.KML.readGxTrack_ = function(node, objectStack) {
48478 var gxTrackObject = ol.xml.pushParseAndPop(
48479 /** @type {ol.KMLGxTrackObject_} */ ({
48480 flatCoordinates: [],
48481 whens: []
48482 }), ol.format.KML.GX_TRACK_PARSERS_, node, objectStack);
48483 if (!gxTrackObject) {
48484 return undefined;
48485 }
48486 var flatCoordinates = gxTrackObject.flatCoordinates;
48487 var whens = gxTrackObject.whens;
48488 var i, ii;
48489 for (i = 0, ii = Math.min(flatCoordinates.length, whens.length); i < ii;
48490 ++i) {
48491 flatCoordinates[4 * i + 3] = whens[i];
48492 }
48493 var lineString = new ol.geom.LineString(null);
48494 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates);
48495 return lineString;
48496};
48497
48498
48499/**
48500 * @param {Node} node Node.
48501 * @param {Array.<*>} objectStack Object stack.
48502 * @private
48503 * @return {Object} Icon object.
48504 */
48505ol.format.KML.readIcon_ = function(node, objectStack) {
48506 var iconObject = ol.xml.pushParseAndPop(
48507 {}, ol.format.KML.ICON_PARSERS_, node, objectStack);
48508 if (iconObject) {
48509 return iconObject;
48510 } else {
48511 return null;
48512 }
48513};
48514
48515
48516/**
48517 * @param {Node} node Node.
48518 * @param {Array.<*>} objectStack Object stack.
48519 * @private
48520 * @return {Array.<number>} Flat coordinates.
48521 */
48522ol.format.KML.readFlatCoordinatesFromNode_ = function(node, objectStack) {
48523 return ol.xml.pushParseAndPop(null,
48524 ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_, node, objectStack);
48525};
48526
48527
48528/**
48529 * @param {Node} node Node.
48530 * @param {Array.<*>} objectStack Object stack.
48531 * @private
48532 * @return {ol.geom.LineString|undefined} LineString.
48533 */
48534ol.format.KML.readLineString_ = function(node, objectStack) {
48535 var properties = ol.xml.pushParseAndPop({},
48536 ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
48537 objectStack);
48538 var flatCoordinates =
48539 ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
48540 if (flatCoordinates) {
48541 var lineString = new ol.geom.LineString(null);
48542 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
48543 lineString.setProperties(properties);
48544 return lineString;
48545 } else {
48546 return undefined;
48547 }
48548};
48549
48550
48551/**
48552 * @param {Node} node Node.
48553 * @param {Array.<*>} objectStack Object stack.
48554 * @private
48555 * @return {ol.geom.Polygon|undefined} Polygon.
48556 */
48557ol.format.KML.readLinearRing_ = function(node, objectStack) {
48558 var properties = ol.xml.pushParseAndPop({},
48559 ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
48560 objectStack);
48561 var flatCoordinates =
48562 ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
48563 if (flatCoordinates) {
48564 var polygon = new ol.geom.Polygon(null);
48565 polygon.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates,
48566 [flatCoordinates.length]);
48567 polygon.setProperties(properties);
48568 return polygon;
48569 } else {
48570 return undefined;
48571 }
48572};
48573
48574
48575/**
48576 * @param {Node} node Node.
48577 * @param {Array.<*>} objectStack Object stack.
48578 * @private
48579 * @return {ol.geom.Geometry} Geometry.
48580 */
48581ol.format.KML.readMultiGeometry_ = function(node, objectStack) {
48582 var geometries = ol.xml.pushParseAndPop([],
48583 ol.format.KML.MULTI_GEOMETRY_PARSERS_, node, objectStack);
48584 if (!geometries) {
48585 return null;
48586 }
48587 if (geometries.length === 0) {
48588 return new ol.geom.GeometryCollection(geometries);
48589 }
48590 /** @type {ol.geom.Geometry} */
48591 var multiGeometry;
48592 var homogeneous = true;
48593 var type = geometries[0].getType();
48594 var geometry, i, ii;
48595 for (i = 1, ii = geometries.length; i < ii; ++i) {
48596 geometry = geometries[i];
48597 if (geometry.getType() != type) {
48598 homogeneous = false;
48599 break;
48600 }
48601 }
48602 if (homogeneous) {
48603 var layout;
48604 var flatCoordinates;
48605 if (type == ol.geom.GeometryType.POINT) {
48606 var point = geometries[0];
48607 layout = point.getLayout();
48608 flatCoordinates = point.getFlatCoordinates();
48609 for (i = 1, ii = geometries.length; i < ii; ++i) {
48610 geometry = geometries[i];
48611 ol.array.extend(flatCoordinates, geometry.getFlatCoordinates());
48612 }
48613 multiGeometry = new ol.geom.MultiPoint(null);
48614 multiGeometry.setFlatCoordinates(layout, flatCoordinates);
48615 ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);
48616 } else if (type == ol.geom.GeometryType.LINE_STRING) {
48617 multiGeometry = new ol.geom.MultiLineString(null);
48618 multiGeometry.setLineStrings(geometries);
48619 ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);
48620 } else if (type == ol.geom.GeometryType.POLYGON) {
48621 multiGeometry = new ol.geom.MultiPolygon(null);
48622 multiGeometry.setPolygons(geometries);
48623 ol.format.KML.setCommonGeometryProperties_(multiGeometry, geometries);
48624 } else if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
48625 multiGeometry = new ol.geom.GeometryCollection(geometries);
48626 } else {
48627 ol.asserts.assert(false, 37); // Unknown geometry type found
48628 }
48629 } else {
48630 multiGeometry = new ol.geom.GeometryCollection(geometries);
48631 }
48632 return /** @type {ol.geom.Geometry} */ (multiGeometry);
48633};
48634
48635
48636/**
48637 * @param {Node} node Node.
48638 * @param {Array.<*>} objectStack Object stack.
48639 * @private
48640 * @return {ol.geom.Point|undefined} Point.
48641 */
48642ol.format.KML.readPoint_ = function(node, objectStack) {
48643 var properties = ol.xml.pushParseAndPop({},
48644 ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
48645 objectStack);
48646 var flatCoordinates =
48647 ol.format.KML.readFlatCoordinatesFromNode_(node, objectStack);
48648 if (flatCoordinates) {
48649 var point = new ol.geom.Point(null);
48650 point.setFlatCoordinates(ol.geom.GeometryLayout.XYZ, flatCoordinates);
48651 point.setProperties(properties);
48652 return point;
48653 } else {
48654 return undefined;
48655 }
48656};
48657
48658
48659/**
48660 * @param {Node} node Node.
48661 * @param {Array.<*>} objectStack Object stack.
48662 * @private
48663 * @return {ol.geom.Polygon|undefined} Polygon.
48664 */
48665ol.format.KML.readPolygon_ = function(node, objectStack) {
48666 var properties = ol.xml.pushParseAndPop(/** @type {Object<string,*>} */ ({}),
48667 ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_, node,
48668 objectStack);
48669 var flatLinearRings = ol.xml.pushParseAndPop([null],
48670 ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_, node, objectStack);
48671 if (flatLinearRings && flatLinearRings[0]) {
48672 var polygon = new ol.geom.Polygon(null);
48673 var flatCoordinates = flatLinearRings[0];
48674 var ends = [flatCoordinates.length];
48675 var i, ii;
48676 for (i = 1, ii = flatLinearRings.length; i < ii; ++i) {
48677 ol.array.extend(flatCoordinates, flatLinearRings[i]);
48678 ends.push(flatCoordinates.length);
48679 }
48680 polygon.setFlatCoordinates(
48681 ol.geom.GeometryLayout.XYZ, flatCoordinates, ends);
48682 polygon.setProperties(properties);
48683 return polygon;
48684 } else {
48685 return undefined;
48686 }
48687};
48688
48689
48690/**
48691 * @param {Node} node Node.
48692 * @param {Array.<*>} objectStack Object stack.
48693 * @private
48694 * @return {Array.<ol.style.Style>} Style.
48695 */
48696ol.format.KML.readStyle_ = function(node, objectStack) {
48697 var styleObject = ol.xml.pushParseAndPop(
48698 {}, ol.format.KML.STYLE_PARSERS_, node, objectStack);
48699 if (!styleObject) {
48700 return null;
48701 }
48702 var fillStyle = /** @type {ol.style.Fill} */
48703 ('fillStyle' in styleObject ?
48704 styleObject['fillStyle'] : ol.format.KML.DEFAULT_FILL_STYLE_);
48705 var fill = /** @type {boolean|undefined} */ (styleObject['fill']);
48706 if (fill !== undefined && !fill) {
48707 fillStyle = null;
48708 }
48709 var imageStyle = /** @type {ol.style.Image} */
48710 ('imageStyle' in styleObject ?
48711 styleObject['imageStyle'] : ol.format.KML.DEFAULT_IMAGE_STYLE_);
48712 if (imageStyle == ol.format.KML.DEFAULT_NO_IMAGE_STYLE_) {
48713 imageStyle = undefined;
48714 }
48715 var textStyle = /** @type {ol.style.Text} */
48716 ('textStyle' in styleObject ?
48717 styleObject['textStyle'] : ol.format.KML.DEFAULT_TEXT_STYLE_);
48718 var strokeStyle = /** @type {ol.style.Stroke} */
48719 ('strokeStyle' in styleObject ?
48720 styleObject['strokeStyle'] : ol.format.KML.DEFAULT_STROKE_STYLE_);
48721 var outline = /** @type {boolean|undefined} */
48722 (styleObject['outline']);
48723 if (outline !== undefined && !outline) {
48724 strokeStyle = null;
48725 }
48726 return [new ol.style.Style({
48727 fill: fillStyle,
48728 image: imageStyle,
48729 stroke: strokeStyle,
48730 text: textStyle,
48731 zIndex: undefined // FIXME
48732 })];
48733};
48734
48735
48736/**
48737 * Reads an array of geometries and creates arrays for common geometry
48738 * properties. Then sets them to the multi geometry.
48739 * @param {ol.geom.MultiPoint|ol.geom.MultiLineString|ol.geom.MultiPolygon}
48740 * multiGeometry A multi-geometry.
48741 * @param {Array.<ol.geom.Geometry>} geometries List of geometries.
48742 * @private
48743 */
48744ol.format.KML.setCommonGeometryProperties_ = function(multiGeometry,
48745 geometries) {
48746 var ii = geometries.length;
48747 var extrudes = new Array(geometries.length);
48748 var tessellates = new Array(geometries.length);
48749 var altitudeModes = new Array(geometries.length);
48750 var geometry, i, hasExtrude, hasTessellate, hasAltitudeMode;
48751 hasExtrude = hasTessellate = hasAltitudeMode = false;
48752 for (i = 0; i < ii; ++i) {
48753 geometry = geometries[i];
48754 extrudes[i] = geometry.get('extrude');
48755 tessellates[i] = geometry.get('tessellate');
48756 altitudeModes[i] = geometry.get('altitudeMode');
48757 hasExtrude = hasExtrude || extrudes[i] !== undefined;
48758 hasTessellate = hasTessellate || tessellates[i] !== undefined;
48759 hasAltitudeMode = hasAltitudeMode || altitudeModes[i];
48760 }
48761 if (hasExtrude) {
48762 multiGeometry.set('extrude', extrudes);
48763 }
48764 if (hasTessellate) {
48765 multiGeometry.set('tessellate', tessellates);
48766 }
48767 if (hasAltitudeMode) {
48768 multiGeometry.set('altitudeMode', altitudeModes);
48769 }
48770};
48771
48772
48773/**
48774 * @param {Node} node Node.
48775 * @param {Array.<*>} objectStack Object stack.
48776 * @private
48777 */
48778ol.format.KML.DataParser_ = function(node, objectStack) {
48779 var name = node.getAttribute('name');
48780 ol.xml.parseNode(ol.format.KML.DATA_PARSERS_, node, objectStack);
48781 var featureObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);
48782 if (name !== null) {
48783 featureObject[name] = featureObject.value;
48784 } else if (featureObject.displayName !== null) {
48785 featureObject[featureObject.displayName] = featureObject.value;
48786 }
48787 delete featureObject['value'];
48788};
48789
48790
48791/**
48792 * @param {Node} node Node.
48793 * @param {Array.<*>} objectStack Object stack.
48794 * @private
48795 */
48796ol.format.KML.ExtendedDataParser_ = function(node, objectStack) {
48797 ol.xml.parseNode(ol.format.KML.EXTENDED_DATA_PARSERS_, node, objectStack);
48798};
48799
48800/**
48801 * @param {Node} node Node.
48802 * @param {Array.<*>} objectStack Object stack.
48803 * @private
48804 */
48805ol.format.KML.RegionParser_ = function(node, objectStack) {
48806 ol.xml.parseNode(ol.format.KML.REGION_PARSERS_, node, objectStack);
48807};
48808
48809/**
48810 * @param {Node} node Node.
48811 * @param {Array.<*>} objectStack Object stack.
48812 * @private
48813 */
48814ol.format.KML.PairDataParser_ = function(node, objectStack) {
48815 var pairObject = ol.xml.pushParseAndPop(
48816 {}, ol.format.KML.PAIR_PARSERS_, node, objectStack);
48817 if (!pairObject) {
48818 return;
48819 }
48820 var key = /** @type {string|undefined} */
48821 (pairObject['key']);
48822 if (key && key == 'normal') {
48823 var styleUrl = /** @type {string|undefined} */
48824 (pairObject['styleUrl']);
48825 if (styleUrl) {
48826 objectStack[objectStack.length - 1] = styleUrl;
48827 }
48828 var Style = /** @type {ol.style.Style} */
48829 (pairObject['Style']);
48830 if (Style) {
48831 objectStack[objectStack.length - 1] = Style;
48832 }
48833 }
48834};
48835
48836
48837/**
48838 * @param {Node} node Node.
48839 * @param {Array.<*>} objectStack Object stack.
48840 * @private
48841 */
48842ol.format.KML.PlacemarkStyleMapParser_ = function(node, objectStack) {
48843 var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);
48844 if (!styleMapValue) {
48845 return;
48846 }
48847 var placemarkObject = objectStack[objectStack.length - 1];
48848 if (Array.isArray(styleMapValue)) {
48849 placemarkObject['Style'] = styleMapValue;
48850 } else if (typeof styleMapValue === 'string') {
48851 placemarkObject['styleUrl'] = styleMapValue;
48852 } else {
48853 ol.asserts.assert(false, 38); // `styleMapValue` has an unknown type
48854 }
48855};
48856
48857
48858/**
48859 * @param {Node} node Node.
48860 * @param {Array.<*>} objectStack Object stack.
48861 * @private
48862 */
48863ol.format.KML.SchemaDataParser_ = function(node, objectStack) {
48864 ol.xml.parseNode(ol.format.KML.SCHEMA_DATA_PARSERS_, node, objectStack);
48865};
48866
48867
48868/**
48869 * @param {Node} node Node.
48870 * @param {Array.<*>} objectStack Object stack.
48871 * @private
48872 */
48873ol.format.KML.SimpleDataParser_ = function(node, objectStack) {
48874 var name = node.getAttribute('name');
48875 if (name !== null) {
48876 var data = ol.format.XSD.readString(node);
48877 var featureObject =
48878 /** @type {Object} */ (objectStack[objectStack.length - 1]);
48879 featureObject[name] = data;
48880 }
48881};
48882
48883
48884/**
48885 * @param {Node} node Node.
48886 * @param {Array.<*>} objectStack Object stack.
48887 * @private
48888 */
48889ol.format.KML.LatLonAltBoxParser_ = function(node, objectStack) {
48890 var object = ol.xml.pushParseAndPop({}, ol.format.KML.LAT_LON_ALT_BOX_PARSERS_, node, objectStack);
48891 if (!object) {
48892 return;
48893 }
48894 var regionObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);
48895 var extent = [
48896 parseFloat(object['west']),
48897 parseFloat(object['south']),
48898 parseFloat(object['east']),
48899 parseFloat(object['north'])
48900 ];
48901 regionObject['extent'] = extent;
48902 regionObject['altitudeMode'] = object['altitudeMode'];
48903 regionObject['minAltitude'] = parseFloat(object['minAltitude']);
48904 regionObject['maxAltitude'] = parseFloat(object['maxAltitude']);
48905};
48906
48907
48908/**
48909 * @param {Node} node Node.
48910 * @param {Array.<*>} objectStack Object stack.
48911 * @private
48912 */
48913ol.format.KML.LodParser_ = function(node, objectStack) {
48914 var object = ol.xml.pushParseAndPop({}, ol.format.KML.LOD_PARSERS_, node, objectStack);
48915 if (!object) {
48916 return;
48917 }
48918 var lodObject = /** @type {Object} */ (objectStack[objectStack.length - 1]);
48919 lodObject['minLodPixels'] = parseFloat(object['minLodPixels']);
48920 lodObject['maxLodPixels'] = parseFloat(object['maxLodPixels']);
48921 lodObject['minFadeExtent'] = parseFloat(object['minFadeExtent']);
48922 lodObject['maxFadeExtent'] = parseFloat(object['maxFadeExtent']);
48923};
48924
48925
48926/**
48927 * @param {Node} node Node.
48928 * @param {Array.<*>} objectStack Object stack.
48929 * @private
48930 */
48931ol.format.KML.innerBoundaryIsParser_ = function(node, objectStack) {
48932 /** @type {Array.<number>|undefined} */
48933 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
48934 ol.format.KML.INNER_BOUNDARY_IS_PARSERS_, node, objectStack);
48935 if (flatLinearRing) {
48936 var flatLinearRings = /** @type {Array.<Array.<number>>} */
48937 (objectStack[objectStack.length - 1]);
48938 flatLinearRings.push(flatLinearRing);
48939 }
48940};
48941
48942
48943/**
48944 * @param {Node} node Node.
48945 * @param {Array.<*>} objectStack Object stack.
48946 * @private
48947 */
48948ol.format.KML.outerBoundaryIsParser_ = function(node, objectStack) {
48949 /** @type {Array.<number>|undefined} */
48950 var flatLinearRing = ol.xml.pushParseAndPop(undefined,
48951 ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_, node, objectStack);
48952 if (flatLinearRing) {
48953 var flatLinearRings = /** @type {Array.<Array.<number>>} */
48954 (objectStack[objectStack.length - 1]);
48955 flatLinearRings[0] = flatLinearRing;
48956 }
48957};
48958
48959
48960/**
48961 * @param {Node} node Node.
48962 * @param {Array.<*>} objectStack Object stack.
48963 * @private
48964 */
48965ol.format.KML.LinkParser_ = function(node, objectStack) {
48966 ol.xml.parseNode(ol.format.KML.LINK_PARSERS_, node, objectStack);
48967};
48968
48969
48970/**
48971 * @param {Node} node Node.
48972 * @param {Array.<*>} objectStack Object stack.
48973 * @private
48974 */
48975ol.format.KML.whenParser_ = function(node, objectStack) {
48976 var gxTrackObject = /** @type {ol.KMLGxTrackObject_} */
48977 (objectStack[objectStack.length - 1]);
48978 var whens = gxTrackObject.whens;
48979 var s = ol.xml.getAllTextContent(node, false);
48980 var when = Date.parse(s);
48981 whens.push(isNaN(when) ? 0 : when);
48982};
48983
48984
48985/**
48986 * @const
48987 * @type {Object.<string, Object.<string, ol.XmlParser>>}
48988 * @private
48989 */
48990ol.format.KML.DATA_PARSERS_ = ol.xml.makeStructureNS(
48991 ol.format.KML.NAMESPACE_URIS_, {
48992 'displayName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
48993 'value': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
48994 });
48995
48996
48997/**
48998 * @const
48999 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49000 * @private
49001 */
49002ol.format.KML.EXTENDED_DATA_PARSERS_ = ol.xml.makeStructureNS(
49003 ol.format.KML.NAMESPACE_URIS_, {
49004 'Data': ol.format.KML.DataParser_,
49005 'SchemaData': ol.format.KML.SchemaDataParser_
49006 });
49007
49008
49009/**
49010 * @const
49011 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49012 * @private
49013 */
49014ol.format.KML.REGION_PARSERS_ = ol.xml.makeStructureNS(
49015 ol.format.KML.NAMESPACE_URIS_, {
49016 'LatLonAltBox': ol.format.KML.LatLonAltBoxParser_,
49017 'Lod': ol.format.KML.LodParser_
49018 });
49019
49020
49021/**
49022 * @const
49023 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49024 * @private
49025 */
49026ol.format.KML.LAT_LON_ALT_BOX_PARSERS_ = ol.xml.makeStructureNS(
49027 ol.format.KML.NAMESPACE_URIS_, {
49028 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49029 'minAltitude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49030 'maxAltitude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49031 'north': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49032 'south': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49033 'east': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49034 'west': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
49035 });
49036
49037
49038/**
49039 * @const
49040 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49041 * @private
49042 */
49043ol.format.KML.LOD_PARSERS_ = ol.xml.makeStructureNS(
49044 ol.format.KML.NAMESPACE_URIS_, {
49045 'minLodPixels': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49046 'maxLodPixels': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49047 'minFadeExtent': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49048 'maxFadeExtent': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
49049 });
49050
49051
49052/**
49053 * @const
49054 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49055 * @private
49056 */
49057ol.format.KML.EXTRUDE_AND_ALTITUDE_MODE_PARSERS_ = ol.xml.makeStructureNS(
49058 ol.format.KML.NAMESPACE_URIS_, {
49059 'extrude': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
49060 'tessellate': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
49061 'altitudeMode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
49062 });
49063
49064
49065/**
49066 * @const
49067 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49068 * @private
49069 */
49070ol.format.KML.FLAT_LINEAR_RING_PARSERS_ = ol.xml.makeStructureNS(
49071 ol.format.KML.NAMESPACE_URIS_, {
49072 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)
49073 });
49074
49075
49076/**
49077 * @const
49078 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49079 * @private
49080 */
49081ol.format.KML.FLAT_LINEAR_RINGS_PARSERS_ = ol.xml.makeStructureNS(
49082 ol.format.KML.NAMESPACE_URIS_, {
49083 'innerBoundaryIs': ol.format.KML.innerBoundaryIsParser_,
49084 'outerBoundaryIs': ol.format.KML.outerBoundaryIsParser_
49085 });
49086
49087
49088/**
49089 * @const
49090 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49091 * @private
49092 */
49093ol.format.KML.GX_TRACK_PARSERS_ = ol.xml.makeStructureNS(
49094 ol.format.KML.NAMESPACE_URIS_, {
49095 'when': ol.format.KML.whenParser_
49096 }, ol.xml.makeStructureNS(
49097 ol.format.KML.GX_NAMESPACE_URIS_, {
49098 'coord': ol.format.KML.gxCoordParser_
49099 }));
49100
49101
49102/**
49103 * @const
49104 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49105 * @private
49106 */
49107ol.format.KML.GEOMETRY_FLAT_COORDINATES_PARSERS_ = ol.xml.makeStructureNS(
49108 ol.format.KML.NAMESPACE_URIS_, {
49109 'coordinates': ol.xml.makeReplacer(ol.format.KML.readFlatCoordinates_)
49110 });
49111
49112
49113/**
49114 * @const
49115 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49116 * @private
49117 */
49118ol.format.KML.ICON_PARSERS_ = ol.xml.makeStructureNS(
49119 ol.format.KML.NAMESPACE_URIS_, {
49120 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)
49121 }, ol.xml.makeStructureNS(
49122 ol.format.KML.GX_NAMESPACE_URIS_, {
49123 'x': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49124 'y': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49125 'w': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49126 'h': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
49127 }));
49128
49129
49130/**
49131 * @const
49132 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49133 * @private
49134 */
49135ol.format.KML.ICON_STYLE_PARSERS_ = ol.xml.makeStructureNS(
49136 ol.format.KML.NAMESPACE_URIS_, {
49137 'Icon': ol.xml.makeObjectPropertySetter(ol.format.KML.readIcon_),
49138 'heading': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal),
49139 'hotSpot': ol.xml.makeObjectPropertySetter(ol.format.KML.readVec2_),
49140 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)
49141 });
49142
49143
49144/**
49145 * @const
49146 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49147 * @private
49148 */
49149ol.format.KML.INNER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(
49150 ol.format.KML.NAMESPACE_URIS_, {
49151 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)
49152 });
49153
49154
49155/**
49156 * @const
49157 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49158 * @private
49159 */
49160ol.format.KML.LABEL_STYLE_PARSERS_ = ol.xml.makeStructureNS(
49161 ol.format.KML.NAMESPACE_URIS_, {
49162 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
49163 'scale': ol.xml.makeObjectPropertySetter(ol.format.KML.readScale_)
49164 });
49165
49166
49167/**
49168 * @const
49169 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49170 * @private
49171 */
49172ol.format.KML.LINE_STYLE_PARSERS_ = ol.xml.makeStructureNS(
49173 ol.format.KML.NAMESPACE_URIS_, {
49174 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
49175 'width': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal)
49176 });
49177
49178
49179/**
49180 * @const
49181 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49182 * @private
49183 */
49184ol.format.KML.MULTI_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(
49185 ol.format.KML.NAMESPACE_URIS_, {
49186 'LineString': ol.xml.makeArrayPusher(ol.format.KML.readLineString_),
49187 'LinearRing': ol.xml.makeArrayPusher(ol.format.KML.readLinearRing_),
49188 'MultiGeometry': ol.xml.makeArrayPusher(ol.format.KML.readMultiGeometry_),
49189 'Point': ol.xml.makeArrayPusher(ol.format.KML.readPoint_),
49190 'Polygon': ol.xml.makeArrayPusher(ol.format.KML.readPolygon_)
49191 });
49192
49193
49194/**
49195 * @const
49196 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49197 * @private
49198 */
49199ol.format.KML.GX_MULTITRACK_GEOMETRY_PARSERS_ = ol.xml.makeStructureNS(
49200 ol.format.KML.GX_NAMESPACE_URIS_, {
49201 'Track': ol.xml.makeArrayPusher(ol.format.KML.readGxTrack_)
49202 });
49203
49204
49205/**
49206 * @const
49207 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49208 * @private
49209 */
49210ol.format.KML.NETWORK_LINK_PARSERS_ = ol.xml.makeStructureNS(
49211 ol.format.KML.NAMESPACE_URIS_, {
49212 'ExtendedData': ol.format.KML.ExtendedDataParser_,
49213 'Region': ol.format.KML.RegionParser_,
49214 'Link': ol.format.KML.LinkParser_,
49215 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49216 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49217 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49218 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
49219 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49220 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
49221 });
49222
49223
49224/**
49225 * @const
49226 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49227 * @private
49228 */
49229ol.format.KML.LINK_PARSERS_ = ol.xml.makeStructureNS(
49230 ol.format.KML.NAMESPACE_URIS_, {
49231 'href': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)
49232 });
49233
49234
49235/**
49236 * @const
49237 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49238 * @private
49239 */
49240ol.format.KML.OUTER_BOUNDARY_IS_PARSERS_ = ol.xml.makeStructureNS(
49241 ol.format.KML.NAMESPACE_URIS_, {
49242 'LinearRing': ol.xml.makeReplacer(ol.format.KML.readFlatLinearRing_)
49243 });
49244
49245
49246/**
49247 * @const
49248 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49249 * @private
49250 */
49251ol.format.KML.PAIR_PARSERS_ = ol.xml.makeStructureNS(
49252 ol.format.KML.NAMESPACE_URIS_, {
49253 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),
49254 'key': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49255 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_)
49256 });
49257
49258
49259/**
49260 * @const
49261 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49262 * @private
49263 */
49264ol.format.KML.PLACEMARK_PARSERS_ = ol.xml.makeStructureNS(
49265 ol.format.KML.NAMESPACE_URIS_, {
49266 'ExtendedData': ol.format.KML.ExtendedDataParser_,
49267 'Region': ol.format.KML.RegionParser_,
49268 'MultiGeometry': ol.xml.makeObjectPropertySetter(
49269 ol.format.KML.readMultiGeometry_, 'geometry'),
49270 'LineString': ol.xml.makeObjectPropertySetter(
49271 ol.format.KML.readLineString_, 'geometry'),
49272 'LinearRing': ol.xml.makeObjectPropertySetter(
49273 ol.format.KML.readLinearRing_, 'geometry'),
49274 'Point': ol.xml.makeObjectPropertySetter(
49275 ol.format.KML.readPoint_, 'geometry'),
49276 'Polygon': ol.xml.makeObjectPropertySetter(
49277 ol.format.KML.readPolygon_, 'geometry'),
49278 'Style': ol.xml.makeObjectPropertySetter(ol.format.KML.readStyle_),
49279 'StyleMap': ol.format.KML.PlacemarkStyleMapParser_,
49280 'address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49281 'description': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49282 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49283 'open': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
49284 'phoneNumber': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
49285 'styleUrl': ol.xml.makeObjectPropertySetter(ol.format.KML.readURI_),
49286 'visibility': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
49287 }, ol.xml.makeStructureNS(
49288 ol.format.KML.GX_NAMESPACE_URIS_, {
49289 'MultiTrack': ol.xml.makeObjectPropertySetter(
49290 ol.format.KML.readGxMultiTrack_, 'geometry'),
49291 'Track': ol.xml.makeObjectPropertySetter(
49292 ol.format.KML.readGxTrack_, 'geometry')
49293 }
49294 ));
49295
49296
49297/**
49298 * @const
49299 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49300 * @private
49301 */
49302ol.format.KML.POLY_STYLE_PARSERS_ = ol.xml.makeStructureNS(
49303 ol.format.KML.NAMESPACE_URIS_, {
49304 'color': ol.xml.makeObjectPropertySetter(ol.format.KML.readColor_),
49305 'fill': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean),
49306 'outline': ol.xml.makeObjectPropertySetter(ol.format.XSD.readBoolean)
49307 });
49308
49309
49310/**
49311 * @const
49312 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49313 * @private
49314 */
49315ol.format.KML.SCHEMA_DATA_PARSERS_ = ol.xml.makeStructureNS(
49316 ol.format.KML.NAMESPACE_URIS_, {
49317 'SimpleData': ol.format.KML.SimpleDataParser_
49318 });
49319
49320
49321/**
49322 * @const
49323 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49324 * @private
49325 */
49326ol.format.KML.STYLE_PARSERS_ = ol.xml.makeStructureNS(
49327 ol.format.KML.NAMESPACE_URIS_, {
49328 'IconStyle': ol.format.KML.IconStyleParser_,
49329 'LabelStyle': ol.format.KML.LabelStyleParser_,
49330 'LineStyle': ol.format.KML.LineStyleParser_,
49331 'PolyStyle': ol.format.KML.PolyStyleParser_
49332 });
49333
49334
49335/**
49336 * @const
49337 * @type {Object.<string, Object.<string, ol.XmlParser>>}
49338 * @private
49339 */
49340ol.format.KML.STYLE_MAP_PARSERS_ = ol.xml.makeStructureNS(
49341 ol.format.KML.NAMESPACE_URIS_, {
49342 'Pair': ol.format.KML.PairDataParser_
49343 });
49344
49345
49346/**
49347 * @param {Node} node Node.
49348 * @param {Array.<*>} objectStack Object stack.
49349 * @private
49350 * @return {Array.<ol.Feature>|undefined} Features.
49351 */
49352ol.format.KML.prototype.readDocumentOrFolder_ = function(node, objectStack) {
49353 // FIXME use scope somehow
49354 var parsersNS = ol.xml.makeStructureNS(
49355 ol.format.KML.NAMESPACE_URIS_, {
49356 'Document': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),
49357 'Folder': ol.xml.makeArrayExtender(this.readDocumentOrFolder_, this),
49358 'Placemark': ol.xml.makeArrayPusher(this.readPlacemark_, this),
49359 'Style': this.readSharedStyle_.bind(this),
49360 'StyleMap': this.readSharedStyleMap_.bind(this)
49361 });
49362 /** @type {Array.<ol.Feature>} */
49363 var features = ol.xml.pushParseAndPop([], parsersNS, node, objectStack, this);
49364 if (features) {
49365 return features;
49366 } else {
49367 return undefined;
49368 }
49369};
49370
49371
49372/**
49373 * @param {Node} node Node.
49374 * @param {Array.<*>} objectStack Object stack.
49375 * @private
49376 * @return {ol.Feature|undefined} Feature.
49377 */
49378ol.format.KML.prototype.readPlacemark_ = function(node, objectStack) {
49379 var object = ol.xml.pushParseAndPop({'geometry': null},
49380 ol.format.KML.PLACEMARK_PARSERS_, node, objectStack);
49381 if (!object) {
49382 return undefined;
49383 }
49384 var feature = new ol.Feature();
49385 var id = node.getAttribute('id');
49386 if (id !== null) {
49387 feature.setId(id);
49388 }
49389 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
49390
49391 var geometry = object['geometry'];
49392 if (geometry) {
49393 ol.format.Feature.transformWithOptions(geometry, false, options);
49394 }
49395 feature.setGeometry(geometry);
49396 delete object['geometry'];
49397
49398 if (this.extractStyles_) {
49399 var style = object['Style'];
49400 var styleUrl = object['styleUrl'];
49401 var styleFunction = ol.format.KML.createFeatureStyleFunction_(
49402 style, styleUrl, this.defaultStyle_, this.sharedStyles_,
49403 this.showPointNames_);
49404 feature.setStyle(styleFunction);
49405 }
49406 delete object['Style'];
49407 // we do not remove the styleUrl property from the object, so it
49408 // gets stored on feature when setProperties is called
49409
49410 feature.setProperties(object);
49411
49412 return feature;
49413};
49414
49415
49416/**
49417 * @param {Node} node Node.
49418 * @param {Array.<*>} objectStack Object stack.
49419 * @private
49420 */
49421ol.format.KML.prototype.readSharedStyle_ = function(node, objectStack) {
49422 var id = node.getAttribute('id');
49423 if (id !== null) {
49424 var style = ol.format.KML.readStyle_(node, objectStack);
49425 if (style) {
49426 var styleUri;
49427 if (node.baseURI && node.baseURI !== 'about:blank') {
49428 var url = new URL('#' + id, node.baseURI);
49429 styleUri = url.href;
49430 } else {
49431 styleUri = '#' + id;
49432 }
49433 this.sharedStyles_[styleUri] = style;
49434 }
49435 }
49436};
49437
49438
49439/**
49440 * @param {Node} node Node.
49441 * @param {Array.<*>} objectStack Object stack.
49442 * @private
49443 */
49444ol.format.KML.prototype.readSharedStyleMap_ = function(node, objectStack) {
49445 var id = node.getAttribute('id');
49446 if (id === null) {
49447 return;
49448 }
49449 var styleMapValue = ol.format.KML.readStyleMapValue_(node, objectStack);
49450 if (!styleMapValue) {
49451 return;
49452 }
49453 var styleUri;
49454 if (node.baseURI && node.baseURI !== 'about:blank') {
49455 var url = new URL('#' + id, node.baseURI);
49456 styleUri = url.href;
49457 } else {
49458 styleUri = '#' + id;
49459 }
49460 this.sharedStyles_[styleUri] = styleMapValue;
49461};
49462
49463
49464/**
49465 * Read the first feature from a KML source. MultiGeometries are converted into
49466 * GeometryCollections if they are a mix of geometry types, and into MultiPoint/
49467 * MultiLineString/MultiPolygon if they are all of the same type.
49468 *
49469 * @function
49470 * @param {Document|Node|Object|string} source Source.
49471 * @param {olx.format.ReadOptions=} opt_options Read options.
49472 * @return {ol.Feature} Feature.
49473 * @api
49474 */
49475ol.format.KML.prototype.readFeature;
49476
49477
49478/**
49479 * @inheritDoc
49480 */
49481ol.format.KML.prototype.readFeatureFromNode = function(node, opt_options) {
49482 if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {
49483 return null;
49484 }
49485 var feature = this.readPlacemark_(
49486 node, [this.getReadOptions(node, opt_options)]);
49487 if (feature) {
49488 return feature;
49489 } else {
49490 return null;
49491 }
49492};
49493
49494
49495/**
49496 * Read all features from a KML source. MultiGeometries are converted into
49497 * GeometryCollections if they are a mix of geometry types, and into MultiPoint/
49498 * MultiLineString/MultiPolygon if they are all of the same type.
49499 *
49500 * @function
49501 * @param {Document|Node|Object|string} source Source.
49502 * @param {olx.format.ReadOptions=} opt_options Read options.
49503 * @return {Array.<ol.Feature>} Features.
49504 * @api
49505 */
49506ol.format.KML.prototype.readFeatures;
49507
49508
49509/**
49510 * @inheritDoc
49511 */
49512ol.format.KML.prototype.readFeaturesFromNode = function(node, opt_options) {
49513 if (!ol.array.includes(ol.format.KML.NAMESPACE_URIS_, node.namespaceURI)) {
49514 return [];
49515 }
49516 var features;
49517 var localName = node.localName;
49518 if (localName == 'Document' || localName == 'Folder') {
49519 features = this.readDocumentOrFolder_(
49520 node, [this.getReadOptions(node, opt_options)]);
49521 if (features) {
49522 return features;
49523 } else {
49524 return [];
49525 }
49526 } else if (localName == 'Placemark') {
49527 var feature = this.readPlacemark_(
49528 node, [this.getReadOptions(node, opt_options)]);
49529 if (feature) {
49530 return [feature];
49531 } else {
49532 return [];
49533 }
49534 } else if (localName == 'kml') {
49535 features = [];
49536 var n;
49537 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49538 var fs = this.readFeaturesFromNode(n, opt_options);
49539 if (fs) {
49540 ol.array.extend(features, fs);
49541 }
49542 }
49543 return features;
49544 } else {
49545 return [];
49546 }
49547};
49548
49549
49550/**
49551 * Read the name of the KML.
49552 *
49553 * @param {Document|Node|string} source Souce.
49554 * @return {string|undefined} Name.
49555 * @api
49556 */
49557ol.format.KML.prototype.readName = function(source) {
49558 if (ol.xml.isDocument(source)) {
49559 return this.readNameFromDocument(/** @type {Document} */ (source));
49560 } else if (ol.xml.isNode(source)) {
49561 return this.readNameFromNode(/** @type {Node} */ (source));
49562 } else if (typeof source === 'string') {
49563 var doc = ol.xml.parse(source);
49564 return this.readNameFromDocument(doc);
49565 } else {
49566 return undefined;
49567 }
49568};
49569
49570
49571/**
49572 * @param {Document} doc Document.
49573 * @return {string|undefined} Name.
49574 */
49575ol.format.KML.prototype.readNameFromDocument = function(doc) {
49576 var n;
49577 for (n = doc.firstChild; n; n = n.nextSibling) {
49578 if (n.nodeType == Node.ELEMENT_NODE) {
49579 var name = this.readNameFromNode(n);
49580 if (name) {
49581 return name;
49582 }
49583 }
49584 }
49585 return undefined;
49586};
49587
49588
49589/**
49590 * @param {Node} node Node.
49591 * @return {string|undefined} Name.
49592 */
49593ol.format.KML.prototype.readNameFromNode = function(node) {
49594 var n;
49595 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49596 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49597 n.localName == 'name') {
49598 return ol.format.XSD.readString(n);
49599 }
49600 }
49601 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49602 var localName = n.localName;
49603 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49604 (localName == 'Document' ||
49605 localName == 'Folder' ||
49606 localName == 'Placemark' ||
49607 localName == 'kml')) {
49608 var name = this.readNameFromNode(n);
49609 if (name) {
49610 return name;
49611 }
49612 }
49613 }
49614 return undefined;
49615};
49616
49617
49618/**
49619 * Read the network links of the KML.
49620 *
49621 * @param {Document|Node|string} source Source.
49622 * @return {Array.<Object>} Network links.
49623 * @api
49624 */
49625ol.format.KML.prototype.readNetworkLinks = function(source) {
49626 var networkLinks = [];
49627 if (ol.xml.isDocument(source)) {
49628 ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(
49629 /** @type {Document} */ (source)));
49630 } else if (ol.xml.isNode(source)) {
49631 ol.array.extend(networkLinks, this.readNetworkLinksFromNode(
49632 /** @type {Node} */ (source)));
49633 } else if (typeof source === 'string') {
49634 var doc = ol.xml.parse(source);
49635 ol.array.extend(networkLinks, this.readNetworkLinksFromDocument(doc));
49636 }
49637 return networkLinks;
49638};
49639
49640
49641/**
49642 * @param {Document} doc Document.
49643 * @return {Array.<Object>} Network links.
49644 */
49645ol.format.KML.prototype.readNetworkLinksFromDocument = function(doc) {
49646 var n, networkLinks = [];
49647 for (n = doc.firstChild; n; n = n.nextSibling) {
49648 if (n.nodeType == Node.ELEMENT_NODE) {
49649 ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));
49650 }
49651 }
49652 return networkLinks;
49653};
49654
49655
49656/**
49657 * @param {Node} node Node.
49658 * @return {Array.<Object>} Network links.
49659 */
49660ol.format.KML.prototype.readNetworkLinksFromNode = function(node) {
49661 var n, networkLinks = [];
49662 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49663 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49664 n.localName == 'NetworkLink') {
49665 var obj = ol.xml.pushParseAndPop({}, ol.format.KML.NETWORK_LINK_PARSERS_,
49666 n, []);
49667 networkLinks.push(obj);
49668 }
49669 }
49670 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49671 var localName = n.localName;
49672 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49673 (localName == 'Document' ||
49674 localName == 'Folder' ||
49675 localName == 'kml')) {
49676 ol.array.extend(networkLinks, this.readNetworkLinksFromNode(n));
49677 }
49678 }
49679 return networkLinks;
49680};
49681
49682
49683/**
49684 * Read the regions of the KML.
49685 *
49686 * @param {Document|Node|string} source Source.
49687 * @return {Array.<Object>} Regions.
49688 * @api
49689 */
49690ol.format.KML.prototype.readRegion = function(source) {
49691 var regions = [];
49692 if (ol.xml.isDocument(source)) {
49693 ol.array.extend(regions, this.readRegionFromDocument(
49694 /** @type {Document} */ (source)));
49695 } else if (ol.xml.isNode(source)) {
49696 ol.array.extend(regions, this.readRegionFromNode(
49697 /** @type {Node} */ (source)));
49698 } else if (typeof source === 'string') {
49699 var doc = ol.xml.parse(source);
49700 ol.array.extend(regions, this.readRegionFromDocument(doc));
49701 }
49702 return regions;
49703};
49704
49705
49706/**
49707 * @param {Document} doc Document.
49708 * @return {Array.<Object>} Region.
49709 */
49710ol.format.KML.prototype.readRegionFromDocument = function(doc) {
49711 var n, regions = [];
49712 for (n = doc.firstChild; n; n = n.nextSibling) {
49713 if (n.nodeType == Node.ELEMENT_NODE) {
49714 ol.array.extend(regions, this.readRegionFromNode(n));
49715 }
49716 }
49717 return regions;
49718};
49719
49720
49721/**
49722 * @param {Node} node Node.
49723 * @return {Array.<Object>} Region.
49724 * @api
49725 */
49726ol.format.KML.prototype.readRegionFromNode = function(node) {
49727 var n, regions = [];
49728 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49729 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49730 n.localName == 'Region') {
49731 var obj = ol.xml.pushParseAndPop({}, ol.format.KML.REGION_PARSERS_,
49732 n, []);
49733 regions.push(obj);
49734 }
49735 }
49736 for (n = node.firstElementChild; n; n = n.nextElementSibling) {
49737 var localName = n.localName;
49738 if (ol.array.includes(ol.format.KML.NAMESPACE_URIS_, n.namespaceURI) &&
49739 (localName == 'Document' ||
49740 localName == 'Folder' ||
49741 localName == 'kml')) {
49742 ol.array.extend(regions, this.readRegionFromNode(n));
49743 }
49744 }
49745 return regions;
49746};
49747
49748
49749/**
49750 * Read the projection from a KML source.
49751 *
49752 * @function
49753 * @param {Document|Node|Object|string} source Source.
49754 * @return {ol.proj.Projection} Projection.
49755 * @api
49756 */
49757ol.format.KML.prototype.readProjection;
49758
49759
49760/**
49761 * @param {Node} node Node to append a TextNode with the color to.
49762 * @param {ol.Color|string} color Color.
49763 * @private
49764 */
49765ol.format.KML.writeColorTextNode_ = function(node, color) {
49766 var rgba = ol.color.asArray(color);
49767 var opacity = (rgba.length == 4) ? rgba[3] : 1;
49768 var abgr = [opacity * 255, rgba[2], rgba[1], rgba[0]];
49769 var i;
49770 for (i = 0; i < 4; ++i) {
49771 var hex = parseInt(abgr[i], 10).toString(16);
49772 abgr[i] = (hex.length == 1) ? '0' + hex : hex;
49773 }
49774 ol.format.XSD.writeStringTextNode(node, abgr.join(''));
49775};
49776
49777
49778/**
49779 * @param {Node} node Node to append a TextNode with the coordinates to.
49780 * @param {Array.<number>} coordinates Coordinates.
49781 * @param {Array.<*>} objectStack Object stack.
49782 * @private
49783 */
49784ol.format.KML.writeCoordinatesTextNode_ = function(node, coordinates, objectStack) {
49785 var context = objectStack[objectStack.length - 1];
49786
49787 var layout = context['layout'];
49788 var stride = context['stride'];
49789
49790 var dimension;
49791 if (layout == ol.geom.GeometryLayout.XY ||
49792 layout == ol.geom.GeometryLayout.XYM) {
49793 dimension = 2;
49794 } else if (layout == ol.geom.GeometryLayout.XYZ ||
49795 layout == ol.geom.GeometryLayout.XYZM) {
49796 dimension = 3;
49797 } else {
49798 ol.asserts.assert(false, 34); // Invalid geometry layout
49799 }
49800
49801 var d, i;
49802 var ii = coordinates.length;
49803 var text = '';
49804 if (ii > 0) {
49805 text += coordinates[0];
49806 for (d = 1; d < dimension; ++d) {
49807 text += ',' + coordinates[d];
49808 }
49809 for (i = stride; i < ii; i += stride) {
49810 text += ' ' + coordinates[i];
49811 for (d = 1; d < dimension; ++d) {
49812 text += ',' + coordinates[i + d];
49813 }
49814 }
49815 }
49816 ol.format.XSD.writeStringTextNode(node, text);
49817};
49818
49819
49820/**
49821 * @param {Node} node Node.
49822 * @param {{name: *, value: *}} pair Name value pair.
49823 * @param {Array.<*>} objectStack Object stack.
49824 * @private
49825 */
49826ol.format.KML.writeDataNode_ = function(node, pair, objectStack) {
49827 node.setAttribute('name', pair.name);
49828 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49829 var value = pair.value;
49830
49831 if (typeof value == 'object') {
49832 if (value !== null && value.displayName) {
49833 ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,
49834 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value.displayName], objectStack, ['displayName']);
49835 }
49836
49837 if (value !== null && value.value) {
49838 ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,
49839 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value.value], objectStack, ['value']);
49840 }
49841 } else {
49842 ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,
49843 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, [value], objectStack, ['value']);
49844 }
49845};
49846
49847
49848/**
49849 * @param {Node} node Node to append a TextNode with the name to.
49850 * @param {string} name DisplayName.
49851 * @private
49852 */
49853ol.format.KML.writeDataNodeName_ = function(node, name) {
49854 ol.format.XSD.writeCDATASection(node, name);
49855};
49856
49857
49858/**
49859 * @param {Node} node Node to append a CDATA Section with the value to.
49860 * @param {string} value Value.
49861 * @private
49862 */
49863ol.format.KML.writeDataNodeValue_ = function(node, value) {
49864 ol.format.XSD.writeStringTextNode(node, value);
49865};
49866
49867
49868/**
49869 * @param {Node} node Node.
49870 * @param {Array.<ol.Feature>} features Features.
49871 * @param {Array.<*>} objectStack Object stack.
49872 * @this {ol.format.KML}
49873 * @private
49874 */
49875ol.format.KML.writeDocument_ = function(node, features, objectStack) {
49876 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49877 ol.xml.pushSerializeAndPop(context, ol.format.KML.DOCUMENT_SERIALIZERS_,
49878 ol.format.KML.DOCUMENT_NODE_FACTORY_, features, objectStack, undefined,
49879 this);
49880};
49881
49882
49883/**
49884 * @param {Node} node Node.
49885 * @param {{names: Array<string>, values: (Array<*>)}} namesAndValues Names and values.
49886 * @param {Array.<*>} objectStack Object stack.
49887 * @private
49888 */
49889ol.format.KML.writeExtendedData_ = function(node, namesAndValues, objectStack) {
49890 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49891 var names = namesAndValues.names, values = namesAndValues.values;
49892 var length = names.length;
49893
49894 for (var i = 0; i < length; i++) {
49895 ol.xml.pushSerializeAndPop(context, ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_,
49896 ol.format.KML.DATA_NODE_FACTORY_, [{name: names[i], value: values[i]}], objectStack);
49897 }
49898};
49899
49900
49901/**
49902 * @param {Node} node Node.
49903 * @param {Object} icon Icon object.
49904 * @param {Array.<*>} objectStack Object stack.
49905 * @private
49906 */
49907ol.format.KML.writeIcon_ = function(node, icon, objectStack) {
49908 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49909 var parentNode = objectStack[objectStack.length - 1].node;
49910 var orderedKeys = ol.format.KML.ICON_SEQUENCE_[parentNode.namespaceURI];
49911 var values = ol.xml.makeSequence(icon, orderedKeys);
49912 ol.xml.pushSerializeAndPop(context,
49913 ol.format.KML.ICON_SERIALIZERS_, ol.xml.OBJECT_PROPERTY_NODE_FACTORY,
49914 values, objectStack, orderedKeys);
49915 orderedKeys =
49916 ol.format.KML.ICON_SEQUENCE_[ol.format.KML.GX_NAMESPACE_URIS_[0]];
49917 values = ol.xml.makeSequence(icon, orderedKeys);
49918 ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_SERIALIZERS_,
49919 ol.format.KML.GX_NODE_FACTORY_, values, objectStack, orderedKeys);
49920};
49921
49922
49923/**
49924 * @param {Node} node Node.
49925 * @param {ol.style.Icon} style Icon style.
49926 * @param {Array.<*>} objectStack Object stack.
49927 * @private
49928 */
49929ol.format.KML.writeIconStyle_ = function(node, style, objectStack) {
49930 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49931 var properties = {};
49932 var src = style.getSrc();
49933 var size = style.getSize();
49934 var iconImageSize = style.getImageSize();
49935 var iconProperties = {
49936 'href': src
49937 };
49938
49939 if (size) {
49940 iconProperties['w'] = size[0];
49941 iconProperties['h'] = size[1];
49942 var anchor = style.getAnchor(); // top-left
49943 var origin = style.getOrigin(); // top-left
49944
49945 if (origin && iconImageSize && origin[0] !== 0 && origin[1] !== size[1]) {
49946 iconProperties['x'] = origin[0];
49947 iconProperties['y'] = iconImageSize[1] - (origin[1] + size[1]);
49948 }
49949
49950 if (anchor && (anchor[0] !== size[0] / 2 || anchor[1] !== size[1] / 2)) {
49951 var /** @type {ol.KMLVec2_} */ hotSpot = {
49952 x: anchor[0],
49953 xunits: ol.style.IconAnchorUnits.PIXELS,
49954 y: size[1] - anchor[1],
49955 yunits: ol.style.IconAnchorUnits.PIXELS
49956 };
49957 properties['hotSpot'] = hotSpot;
49958 }
49959 }
49960
49961 properties['Icon'] = iconProperties;
49962
49963 var scale = style.getScale();
49964 if (scale !== 1) {
49965 properties['scale'] = scale;
49966 }
49967
49968 var rotation = style.getRotation();
49969 if (rotation !== 0) {
49970 properties['heading'] = rotation; // 0-360
49971 }
49972
49973 var parentNode = objectStack[objectStack.length - 1].node;
49974 var orderedKeys = ol.format.KML.ICON_STYLE_SEQUENCE_[parentNode.namespaceURI];
49975 var values = ol.xml.makeSequence(properties, orderedKeys);
49976 ol.xml.pushSerializeAndPop(context, ol.format.KML.ICON_STYLE_SERIALIZERS_,
49977 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
49978};
49979
49980
49981/**
49982 * @param {Node} node Node.
49983 * @param {ol.style.Text} style style.
49984 * @param {Array.<*>} objectStack Object stack.
49985 * @private
49986 */
49987ol.format.KML.writeLabelStyle_ = function(node, style, objectStack) {
49988 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
49989 var properties = {};
49990 var fill = style.getFill();
49991 if (fill) {
49992 properties['color'] = fill.getColor();
49993 }
49994 var scale = style.getScale();
49995 if (scale && scale !== 1) {
49996 properties['scale'] = scale;
49997 }
49998 var parentNode = objectStack[objectStack.length - 1].node;
49999 var orderedKeys =
50000 ol.format.KML.LABEL_STYLE_SEQUENCE_[parentNode.namespaceURI];
50001 var values = ol.xml.makeSequence(properties, orderedKeys);
50002 ol.xml.pushSerializeAndPop(context, ol.format.KML.LABEL_STYLE_SERIALIZERS_,
50003 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
50004};
50005
50006
50007/**
50008 * @param {Node} node Node.
50009 * @param {ol.style.Stroke} style style.
50010 * @param {Array.<*>} objectStack Object stack.
50011 * @private
50012 */
50013ol.format.KML.writeLineStyle_ = function(node, style, objectStack) {
50014 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50015 var properties = {
50016 'color': style.getColor(),
50017 'width': style.getWidth()
50018 };
50019 var parentNode = objectStack[objectStack.length - 1].node;
50020 var orderedKeys = ol.format.KML.LINE_STYLE_SEQUENCE_[parentNode.namespaceURI];
50021 var values = ol.xml.makeSequence(properties, orderedKeys);
50022 ol.xml.pushSerializeAndPop(context, ol.format.KML.LINE_STYLE_SERIALIZERS_,
50023 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
50024};
50025
50026
50027/**
50028 * @param {Node} node Node.
50029 * @param {ol.geom.Geometry} geometry Geometry.
50030 * @param {Array.<*>} objectStack Object stack.
50031 * @private
50032 */
50033ol.format.KML.writeMultiGeometry_ = function(node, geometry, objectStack) {
50034 /** @type {ol.XmlNodeStackItem} */
50035 var context = {node: node};
50036 var type = geometry.getType();
50037 /** @type {Array.<ol.geom.Geometry>} */
50038 var geometries;
50039 /** @type {function(*, Array.<*>, string=): (Node|undefined)} */
50040 var factory;
50041 if (type == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
50042 geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();
50043 factory = ol.format.KML.GEOMETRY_NODE_FACTORY_;
50044 } else if (type == ol.geom.GeometryType.MULTI_POINT) {
50045 geometries = /** @type {ol.geom.MultiPoint} */ (geometry).getPoints();
50046 factory = ol.format.KML.POINT_NODE_FACTORY_;
50047 } else if (type == ol.geom.GeometryType.MULTI_LINE_STRING) {
50048 geometries =
50049 (/** @type {ol.geom.MultiLineString} */ (geometry)).getLineStrings();
50050 factory = ol.format.KML.LINE_STRING_NODE_FACTORY_;
50051 } else if (type == ol.geom.GeometryType.MULTI_POLYGON) {
50052 geometries =
50053 (/** @type {ol.geom.MultiPolygon} */ (geometry)).getPolygons();
50054 factory = ol.format.KML.POLYGON_NODE_FACTORY_;
50055 } else {
50056 ol.asserts.assert(false, 39); // Unknown geometry type
50057 }
50058 ol.xml.pushSerializeAndPop(context,
50059 ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_, factory,
50060 geometries, objectStack);
50061};
50062
50063
50064/**
50065 * @param {Node} node Node.
50066 * @param {ol.geom.LinearRing} linearRing Linear ring.
50067 * @param {Array.<*>} objectStack Object stack.
50068 * @private
50069 */
50070ol.format.KML.writeBoundaryIs_ = function(node, linearRing, objectStack) {
50071 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50072 ol.xml.pushSerializeAndPop(context,
50073 ol.format.KML.BOUNDARY_IS_SERIALIZERS_,
50074 ol.format.KML.LINEAR_RING_NODE_FACTORY_, [linearRing], objectStack);
50075};
50076
50077
50078/**
50079 * FIXME currently we do serialize arbitrary/custom feature properties
50080 * (ExtendedData).
50081 * @param {Node} node Node.
50082 * @param {ol.Feature} feature Feature.
50083 * @param {Array.<*>} objectStack Object stack.
50084 * @this {ol.format.KML}
50085 * @private
50086 */
50087ol.format.KML.writePlacemark_ = function(node, feature, objectStack) {
50088 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50089
50090 // set id
50091 if (feature.getId()) {
50092 node.setAttribute('id', feature.getId());
50093 }
50094
50095 // serialize properties (properties unknown to KML are not serialized)
50096 var properties = feature.getProperties();
50097
50098 // don't export these to ExtendedData
50099 var filter = {'address': 1, 'description': 1, 'name': 1, 'open': 1,
50100 'phoneNumber': 1, 'styleUrl': 1, 'visibility': 1};
50101 filter[feature.getGeometryName()] = 1;
50102 var keys = Object.keys(properties || {}).sort().filter(function(v) {
50103 return !filter[v];
50104 });
50105
50106 if (keys.length > 0) {
50107 var sequence = ol.xml.makeSequence(properties, keys);
50108 var namesAndValues = {names: keys, values: sequence};
50109 ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
50110 ol.format.KML.EXTENDEDDATA_NODE_FACTORY_, [namesAndValues], objectStack);
50111 }
50112
50113 var styleFunction = feature.getStyleFunction();
50114 if (styleFunction) {
50115 // FIXME the styles returned by the style function are supposed to be
50116 // resolution-independent here
50117 var styles = styleFunction.call(feature, 0);
50118 if (styles) {
50119 var style = Array.isArray(styles) ? styles[0] : styles;
50120 if (this.writeStyles_) {
50121 properties['Style'] = style;
50122 }
50123 var textStyle = style.getText();
50124 if (textStyle) {
50125 properties['name'] = textStyle.getText();
50126 }
50127 }
50128 }
50129 var parentNode = objectStack[objectStack.length - 1].node;
50130 var orderedKeys = ol.format.KML.PLACEMARK_SEQUENCE_[parentNode.namespaceURI];
50131 var values = ol.xml.makeSequence(properties, orderedKeys);
50132 ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
50133 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
50134
50135 // serialize geometry
50136 var options = /** @type {olx.format.WriteOptions} */ (objectStack[0]);
50137 var geometry = feature.getGeometry();
50138 if (geometry) {
50139 geometry =
50140 ol.format.Feature.transformWithOptions(geometry, true, options);
50141 }
50142 ol.xml.pushSerializeAndPop(context, ol.format.KML.PLACEMARK_SERIALIZERS_,
50143 ol.format.KML.GEOMETRY_NODE_FACTORY_, [geometry], objectStack);
50144};
50145
50146
50147/**
50148 * @param {Node} node Node.
50149 * @param {ol.geom.SimpleGeometry} geometry Geometry.
50150 * @param {Array.<*>} objectStack Object stack.
50151 * @private
50152 */
50153ol.format.KML.writePrimitiveGeometry_ = function(node, geometry, objectStack) {
50154 var flatCoordinates = geometry.getFlatCoordinates();
50155 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50156 context['layout'] = geometry.getLayout();
50157 context['stride'] = geometry.getStride();
50158
50159 // serialize properties (properties unknown to KML are not serialized)
50160 var properties = geometry.getProperties();
50161 properties.coordinates = flatCoordinates;
50162
50163 var parentNode = objectStack[objectStack.length - 1].node;
50164 var orderedKeys = ol.format.KML.PRIMITIVE_GEOMETRY_SEQUENCE_[parentNode.namespaceURI];
50165 var values = ol.xml.makeSequence(properties, orderedKeys);
50166 ol.xml.pushSerializeAndPop(context, ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_,
50167 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
50168};
50169
50170
50171/**
50172 * @param {Node} node Node.
50173 * @param {ol.geom.Polygon} polygon Polygon.
50174 * @param {Array.<*>} objectStack Object stack.
50175 * @private
50176 */
50177ol.format.KML.writePolygon_ = function(node, polygon, objectStack) {
50178 var linearRings = polygon.getLinearRings();
50179 var outerRing = linearRings.shift();
50180 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50181 // inner rings
50182 ol.xml.pushSerializeAndPop(context,
50183 ol.format.KML.POLYGON_SERIALIZERS_,
50184 ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_,
50185 linearRings, objectStack);
50186 // outer ring
50187 ol.xml.pushSerializeAndPop(context,
50188 ol.format.KML.POLYGON_SERIALIZERS_,
50189 ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_,
50190 [outerRing], objectStack);
50191};
50192
50193
50194/**
50195 * @param {Node} node Node.
50196 * @param {ol.style.Fill} style Style.
50197 * @param {Array.<*>} objectStack Object stack.
50198 * @private
50199 */
50200ol.format.KML.writePolyStyle_ = function(node, style, objectStack) {
50201 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50202 ol.xml.pushSerializeAndPop(context, ol.format.KML.POLY_STYLE_SERIALIZERS_,
50203 ol.format.KML.COLOR_NODE_FACTORY_, [style.getColor()], objectStack);
50204};
50205
50206
50207/**
50208 * @param {Node} node Node to append a TextNode with the scale to.
50209 * @param {number|undefined} scale Scale.
50210 * @private
50211 */
50212ol.format.KML.writeScaleTextNode_ = function(node, scale) {
50213 // the Math is to remove any excess decimals created by float arithmetic
50214 ol.format.XSD.writeDecimalTextNode(node,
50215 Math.round(scale * 1e6) / 1e6);
50216};
50217
50218
50219/**
50220 * @param {Node} node Node.
50221 * @param {ol.style.Style} style Style.
50222 * @param {Array.<*>} objectStack Object stack.
50223 * @private
50224 */
50225ol.format.KML.writeStyle_ = function(node, style, objectStack) {
50226 var /** @type {ol.XmlNodeStackItem} */ context = {node: node};
50227 var properties = {};
50228 var fillStyle = style.getFill();
50229 var strokeStyle = style.getStroke();
50230 var imageStyle = style.getImage();
50231 var textStyle = style.getText();
50232 if (imageStyle instanceof ol.style.Icon) {
50233 properties['IconStyle'] = imageStyle;
50234 }
50235 if (textStyle) {
50236 properties['LabelStyle'] = textStyle;
50237 }
50238 if (strokeStyle) {
50239 properties['LineStyle'] = strokeStyle;
50240 }
50241 if (fillStyle) {
50242 properties['PolyStyle'] = fillStyle;
50243 }
50244 var parentNode = objectStack[objectStack.length - 1].node;
50245 var orderedKeys = ol.format.KML.STYLE_SEQUENCE_[parentNode.namespaceURI];
50246 var values = ol.xml.makeSequence(properties, orderedKeys);
50247 ol.xml.pushSerializeAndPop(context, ol.format.KML.STYLE_SERIALIZERS_,
50248 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, objectStack, orderedKeys);
50249};
50250
50251
50252/**
50253 * @param {Node} node Node to append a TextNode with the Vec2 to.
50254 * @param {ol.KMLVec2_} vec2 Vec2.
50255 * @private
50256 */
50257ol.format.KML.writeVec2_ = function(node, vec2) {
50258 node.setAttribute('x', vec2.x);
50259 node.setAttribute('y', vec2.y);
50260 node.setAttribute('xunits', vec2.xunits);
50261 node.setAttribute('yunits', vec2.yunits);
50262};
50263
50264
50265/**
50266 * @const
50267 * @type {Object.<string, Array.<string>>}
50268 * @private
50269 */
50270ol.format.KML.KML_SEQUENCE_ = ol.xml.makeStructureNS(
50271 ol.format.KML.NAMESPACE_URIS_, [
50272 'Document', 'Placemark'
50273 ]);
50274
50275
50276/**
50277 * @const
50278 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50279 * @private
50280 */
50281ol.format.KML.KML_SERIALIZERS_ = ol.xml.makeStructureNS(
50282 ol.format.KML.NAMESPACE_URIS_, {
50283 'Document': ol.xml.makeChildAppender(ol.format.KML.writeDocument_),
50284 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
50285 });
50286
50287
50288/**
50289 * @const
50290 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50291 * @private
50292 */
50293ol.format.KML.DOCUMENT_SERIALIZERS_ = ol.xml.makeStructureNS(
50294 ol.format.KML.NAMESPACE_URIS_, {
50295 'Placemark': ol.xml.makeChildAppender(ol.format.KML.writePlacemark_)
50296 });
50297
50298
50299/**
50300 * @const
50301 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50302 * @private
50303 */
50304ol.format.KML.EXTENDEDDATA_NODE_SERIALIZERS_ = ol.xml.makeStructureNS(
50305 ol.format.KML.NAMESPACE_URIS_, {
50306 'Data': ol.xml.makeChildAppender(ol.format.KML.writeDataNode_),
50307 'value': ol.xml.makeChildAppender(ol.format.KML.writeDataNodeValue_),
50308 'displayName': ol.xml.makeChildAppender(ol.format.KML.writeDataNodeName_)
50309 });
50310
50311
50312/**
50313 * @const
50314 * @type {Object.<string, string>}
50315 * @private
50316 */
50317ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_ = {
50318 'Point': 'Point',
50319 'LineString': 'LineString',
50320 'LinearRing': 'LinearRing',
50321 'Polygon': 'Polygon',
50322 'MultiPoint': 'MultiGeometry',
50323 'MultiLineString': 'MultiGeometry',
50324 'MultiPolygon': 'MultiGeometry',
50325 'GeometryCollection': 'MultiGeometry'
50326};
50327
50328/**
50329 * @const
50330 * @type {Object.<string, Array.<string>>}
50331 * @private
50332 */
50333ol.format.KML.ICON_SEQUENCE_ = ol.xml.makeStructureNS(
50334 ol.format.KML.NAMESPACE_URIS_, [
50335 'href'
50336 ],
50337 ol.xml.makeStructureNS(ol.format.KML.GX_NAMESPACE_URIS_, [
50338 'x', 'y', 'w', 'h'
50339 ]));
50340
50341
50342/**
50343 * @const
50344 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50345 * @private
50346 */
50347ol.format.KML.ICON_SERIALIZERS_ = ol.xml.makeStructureNS(
50348 ol.format.KML.NAMESPACE_URIS_, {
50349 'href': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
50350 }, ol.xml.makeStructureNS(
50351 ol.format.KML.GX_NAMESPACE_URIS_, {
50352 'x': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
50353 'y': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
50354 'w': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
50355 'h': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
50356 }));
50357
50358
50359/**
50360 * @const
50361 * @type {Object.<string, Array.<string>>}
50362 * @private
50363 */
50364ol.format.KML.ICON_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
50365 ol.format.KML.NAMESPACE_URIS_, [
50366 'scale', 'heading', 'Icon', 'hotSpot'
50367 ]);
50368
50369
50370/**
50371 * @const
50372 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50373 * @private
50374 */
50375ol.format.KML.ICON_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
50376 ol.format.KML.NAMESPACE_URIS_, {
50377 'Icon': ol.xml.makeChildAppender(ol.format.KML.writeIcon_),
50378 'heading': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode),
50379 'hotSpot': ol.xml.makeChildAppender(ol.format.KML.writeVec2_),
50380 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
50381 });
50382
50383
50384/**
50385 * @const
50386 * @type {Object.<string, Array.<string>>}
50387 * @private
50388 */
50389ol.format.KML.LABEL_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
50390 ol.format.KML.NAMESPACE_URIS_, [
50391 'color', 'scale'
50392 ]);
50393
50394
50395/**
50396 * @const
50397 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50398 * @private
50399 */
50400ol.format.KML.LABEL_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
50401 ol.format.KML.NAMESPACE_URIS_, {
50402 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
50403 'scale': ol.xml.makeChildAppender(ol.format.KML.writeScaleTextNode_)
50404 });
50405
50406
50407/**
50408 * @const
50409 * @type {Object.<string, Array.<string>>}
50410 * @private
50411 */
50412ol.format.KML.LINE_STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
50413 ol.format.KML.NAMESPACE_URIS_, [
50414 'color', 'width'
50415 ]);
50416
50417
50418/**
50419 * @const
50420 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50421 * @private
50422 */
50423ol.format.KML.LINE_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
50424 ol.format.KML.NAMESPACE_URIS_, {
50425 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_),
50426 'width': ol.xml.makeChildAppender(ol.format.XSD.writeDecimalTextNode)
50427 });
50428
50429
50430/**
50431 * @const
50432 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50433 * @private
50434 */
50435ol.format.KML.BOUNDARY_IS_SERIALIZERS_ = ol.xml.makeStructureNS(
50436 ol.format.KML.NAMESPACE_URIS_, {
50437 'LinearRing': ol.xml.makeChildAppender(
50438 ol.format.KML.writePrimitiveGeometry_)
50439 });
50440
50441
50442/**
50443 * @const
50444 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50445 * @private
50446 */
50447ol.format.KML.MULTI_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
50448 ol.format.KML.NAMESPACE_URIS_, {
50449 'LineString': ol.xml.makeChildAppender(
50450 ol.format.KML.writePrimitiveGeometry_),
50451 'Point': ol.xml.makeChildAppender(
50452 ol.format.KML.writePrimitiveGeometry_),
50453 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),
50454 'GeometryCollection': ol.xml.makeChildAppender(
50455 ol.format.KML.writeMultiGeometry_)
50456 });
50457
50458
50459/**
50460 * @const
50461 * @type {Object.<string, Array.<string>>}
50462 * @private
50463 */
50464ol.format.KML.PLACEMARK_SEQUENCE_ = ol.xml.makeStructureNS(
50465 ol.format.KML.NAMESPACE_URIS_, [
50466 'name', 'open', 'visibility', 'address', 'phoneNumber', 'description',
50467 'styleUrl', 'Style'
50468 ]);
50469
50470
50471/**
50472 * @const
50473 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50474 * @private
50475 */
50476ol.format.KML.PLACEMARK_SERIALIZERS_ = ol.xml.makeStructureNS(
50477 ol.format.KML.NAMESPACE_URIS_, {
50478 'ExtendedData': ol.xml.makeChildAppender(
50479 ol.format.KML.writeExtendedData_),
50480 'MultiGeometry': ol.xml.makeChildAppender(
50481 ol.format.KML.writeMultiGeometry_),
50482 'LineString': ol.xml.makeChildAppender(
50483 ol.format.KML.writePrimitiveGeometry_),
50484 'LinearRing': ol.xml.makeChildAppender(
50485 ol.format.KML.writePrimitiveGeometry_),
50486 'Point': ol.xml.makeChildAppender(
50487 ol.format.KML.writePrimitiveGeometry_),
50488 'Polygon': ol.xml.makeChildAppender(ol.format.KML.writePolygon_),
50489 'Style': ol.xml.makeChildAppender(ol.format.KML.writeStyle_),
50490 'address': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
50491 'description': ol.xml.makeChildAppender(
50492 ol.format.XSD.writeStringTextNode),
50493 'name': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
50494 'open': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode),
50495 'phoneNumber': ol.xml.makeChildAppender(
50496 ol.format.XSD.writeStringTextNode),
50497 'styleUrl': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
50498 'visibility': ol.xml.makeChildAppender(
50499 ol.format.XSD.writeBooleanTextNode)
50500 });
50501
50502
50503/**
50504 * @const
50505 * @type {Object.<string, Array.<string>>}
50506 * @private
50507 */
50508ol.format.KML.PRIMITIVE_GEOMETRY_SEQUENCE_ = ol.xml.makeStructureNS(
50509 ol.format.KML.NAMESPACE_URIS_, [
50510 'extrude', 'tessellate', 'altitudeMode', 'coordinates'
50511 ]);
50512
50513
50514/**
50515 * @const
50516 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50517 * @private
50518 */
50519ol.format.KML.PRIMITIVE_GEOMETRY_SERIALIZERS_ = ol.xml.makeStructureNS(
50520 ol.format.KML.NAMESPACE_URIS_, {
50521 'extrude': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode),
50522 'tessellate': ol.xml.makeChildAppender(ol.format.XSD.writeBooleanTextNode),
50523 'altitudeMode': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode),
50524 'coordinates': ol.xml.makeChildAppender(
50525 ol.format.KML.writeCoordinatesTextNode_)
50526 });
50527
50528
50529/**
50530 * @const
50531 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50532 * @private
50533 */
50534ol.format.KML.POLYGON_SERIALIZERS_ = ol.xml.makeStructureNS(
50535 ol.format.KML.NAMESPACE_URIS_, {
50536 'outerBoundaryIs': ol.xml.makeChildAppender(
50537 ol.format.KML.writeBoundaryIs_),
50538 'innerBoundaryIs': ol.xml.makeChildAppender(
50539 ol.format.KML.writeBoundaryIs_)
50540 });
50541
50542
50543/**
50544 * @const
50545 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50546 * @private
50547 */
50548ol.format.KML.POLY_STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
50549 ol.format.KML.NAMESPACE_URIS_, {
50550 'color': ol.xml.makeChildAppender(ol.format.KML.writeColorTextNode_)
50551 });
50552
50553
50554/**
50555 * @const
50556 * @type {Object.<string, Array.<string>>}
50557 * @private
50558 */
50559ol.format.KML.STYLE_SEQUENCE_ = ol.xml.makeStructureNS(
50560 ol.format.KML.NAMESPACE_URIS_, [
50561 'IconStyle', 'LabelStyle', 'LineStyle', 'PolyStyle'
50562 ]);
50563
50564
50565/**
50566 * @const
50567 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
50568 * @private
50569 */
50570ol.format.KML.STYLE_SERIALIZERS_ = ol.xml.makeStructureNS(
50571 ol.format.KML.NAMESPACE_URIS_, {
50572 'IconStyle': ol.xml.makeChildAppender(ol.format.KML.writeIconStyle_),
50573 'LabelStyle': ol.xml.makeChildAppender(ol.format.KML.writeLabelStyle_),
50574 'LineStyle': ol.xml.makeChildAppender(ol.format.KML.writeLineStyle_),
50575 'PolyStyle': ol.xml.makeChildAppender(ol.format.KML.writePolyStyle_)
50576 });
50577
50578
50579/**
50580 * @const
50581 * @param {*} value Value.
50582 * @param {Array.<*>} objectStack Object stack.
50583 * @param {string=} opt_nodeName Node name.
50584 * @return {Node|undefined} Node.
50585 * @private
50586 */
50587ol.format.KML.GX_NODE_FACTORY_ = function(value, objectStack, opt_nodeName) {
50588 return ol.xml.createElementNS(ol.format.KML.GX_NAMESPACE_URIS_[0],
50589 'gx:' + opt_nodeName);
50590};
50591
50592
50593/**
50594 * @const
50595 * @param {*} value Value.
50596 * @param {Array.<*>} objectStack Object stack.
50597 * @param {string=} opt_nodeName Node name.
50598 * @return {Node|undefined} Node.
50599 * @private
50600 */
50601ol.format.KML.DOCUMENT_NODE_FACTORY_ = function(value, objectStack,
50602 opt_nodeName) {
50603 var parentNode = objectStack[objectStack.length - 1].node;
50604 return ol.xml.createElementNS(parentNode.namespaceURI, 'Placemark');
50605};
50606
50607
50608/**
50609 * @const
50610 * @param {*} value Value.
50611 * @param {Array.<*>} objectStack Object stack.
50612 * @param {string=} opt_nodeName Node name.
50613 * @return {Node|undefined} Node.
50614 * @private
50615 */
50616ol.format.KML.GEOMETRY_NODE_FACTORY_ = function(value, objectStack,
50617 opt_nodeName) {
50618 if (value) {
50619 var parentNode = objectStack[objectStack.length - 1].node;
50620 return ol.xml.createElementNS(parentNode.namespaceURI,
50621 ol.format.KML.GEOMETRY_TYPE_TO_NODENAME_[/** @type {ol.geom.Geometry} */ (value).getType()]);
50622 }
50623};
50624
50625
50626/**
50627 * A factory for creating coordinates nodes.
50628 * @const
50629 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50630 * @private
50631 */
50632ol.format.KML.COLOR_NODE_FACTORY_ = ol.xml.makeSimpleNodeFactory('color');
50633
50634
50635/**
50636 * A factory for creating Data nodes.
50637 * @const
50638 * @type {function(*, Array.<*>): (Node|undefined)}
50639 * @private
50640 */
50641ol.format.KML.DATA_NODE_FACTORY_ =
50642 ol.xml.makeSimpleNodeFactory('Data');
50643
50644
50645/**
50646 * A factory for creating ExtendedData nodes.
50647 * @const
50648 * @type {function(*, Array.<*>): (Node|undefined)}
50649 * @private
50650 */
50651ol.format.KML.EXTENDEDDATA_NODE_FACTORY_ =
50652 ol.xml.makeSimpleNodeFactory('ExtendedData');
50653
50654
50655/**
50656 * A factory for creating innerBoundaryIs nodes.
50657 * @const
50658 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50659 * @private
50660 */
50661ol.format.KML.INNER_BOUNDARY_NODE_FACTORY_ =
50662 ol.xml.makeSimpleNodeFactory('innerBoundaryIs');
50663
50664
50665/**
50666 * A factory for creating Point nodes.
50667 * @const
50668 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50669 * @private
50670 */
50671ol.format.KML.POINT_NODE_FACTORY_ =
50672 ol.xml.makeSimpleNodeFactory('Point');
50673
50674
50675/**
50676 * A factory for creating LineString nodes.
50677 * @const
50678 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50679 * @private
50680 */
50681ol.format.KML.LINE_STRING_NODE_FACTORY_ =
50682 ol.xml.makeSimpleNodeFactory('LineString');
50683
50684
50685/**
50686 * A factory for creating LinearRing nodes.
50687 * @const
50688 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50689 * @private
50690 */
50691ol.format.KML.LINEAR_RING_NODE_FACTORY_ =
50692 ol.xml.makeSimpleNodeFactory('LinearRing');
50693
50694
50695/**
50696 * A factory for creating Polygon nodes.
50697 * @const
50698 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50699 * @private
50700 */
50701ol.format.KML.POLYGON_NODE_FACTORY_ =
50702 ol.xml.makeSimpleNodeFactory('Polygon');
50703
50704
50705/**
50706 * A factory for creating outerBoundaryIs nodes.
50707 * @const
50708 * @type {function(*, Array.<*>, string=): (Node|undefined)}
50709 * @private
50710 */
50711ol.format.KML.OUTER_BOUNDARY_NODE_FACTORY_ =
50712 ol.xml.makeSimpleNodeFactory('outerBoundaryIs');
50713
50714
50715/**
50716 * Encode an array of features in the KML format. GeometryCollections, MultiPoints,
50717 * MultiLineStrings, and MultiPolygons are output as MultiGeometries.
50718 *
50719 * @function
50720 * @param {Array.<ol.Feature>} features Features.
50721 * @param {olx.format.WriteOptions=} opt_options Options.
50722 * @return {string} Result.
50723 * @api
50724 */
50725ol.format.KML.prototype.writeFeatures;
50726
50727
50728/**
50729 * Encode an array of features in the KML format as an XML node. GeometryCollections,
50730 * MultiPoints, MultiLineStrings, and MultiPolygons are output as MultiGeometries.
50731 *
50732 * @param {Array.<ol.Feature>} features Features.
50733 * @param {olx.format.WriteOptions=} opt_options Options.
50734 * @return {Node} Node.
50735 * @override
50736 * @api
50737 */
50738ol.format.KML.prototype.writeFeaturesNode = function(features, opt_options) {
50739 opt_options = this.adaptOptions(opt_options);
50740 var kml = ol.xml.createElementNS(ol.format.KML.NAMESPACE_URIS_[4], 'kml');
50741 var xmlnsUri = 'http://www.w3.org/2000/xmlns/';
50742 var xmlSchemaInstanceUri = 'http://www.w3.org/2001/XMLSchema-instance';
50743 ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:gx',
50744 ol.format.KML.GX_NAMESPACE_URIS_[0]);
50745 ol.xml.setAttributeNS(kml, xmlnsUri, 'xmlns:xsi', xmlSchemaInstanceUri);
50746 ol.xml.setAttributeNS(kml, xmlSchemaInstanceUri, 'xsi:schemaLocation',
50747 ol.format.KML.SCHEMA_LOCATION_);
50748
50749 var /** @type {ol.XmlNodeStackItem} */ context = {node: kml};
50750 var properties = {};
50751 if (features.length > 1) {
50752 properties['Document'] = features;
50753 } else if (features.length == 1) {
50754 properties['Placemark'] = features[0];
50755 }
50756 var orderedKeys = ol.format.KML.KML_SEQUENCE_[kml.namespaceURI];
50757 var values = ol.xml.makeSequence(properties, orderedKeys);
50758 ol.xml.pushSerializeAndPop(context, ol.format.KML.KML_SERIALIZERS_,
50759 ol.xml.OBJECT_PROPERTY_NODE_FACTORY, values, [opt_options], orderedKeys,
50760 this);
50761 return kml;
50762};
50763
50764
50765/**
50766 * @fileoverview
50767 * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, unusedLocalVariables, uselessCode, visibility}
50768 */
50769goog.provide('ol.ext.PBF');
50770
50771/** @typedef {function(*)} */
50772ol.ext.PBF = function() {};
50773
50774(function() {(function (exports) {
50775'use strict';
50776
50777var read = function (buffer, offset, isLE, mLen, nBytes) {
50778 var e, m;
50779 var eLen = nBytes * 8 - mLen - 1;
50780 var eMax = (1 << eLen) - 1;
50781 var eBias = eMax >> 1;
50782 var nBits = -7;
50783 var i = isLE ? (nBytes - 1) : 0;
50784 var d = isLE ? -1 : 1;
50785 var s = buffer[offset + i];
50786 i += d;
50787 e = s & ((1 << (-nBits)) - 1);
50788 s >>= (-nBits);
50789 nBits += eLen;
50790 for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50791 m = e & ((1 << (-nBits)) - 1);
50792 e >>= (-nBits);
50793 nBits += mLen;
50794 for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50795 if (e === 0) {
50796 e = 1 - eBias;
50797 } else if (e === eMax) {
50798 return m ? NaN : ((s ? -1 : 1) * Infinity)
50799 } else {
50800 m = m + Math.pow(2, mLen);
50801 e = e - eBias;
50802 }
50803 return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
50804};
50805var write = function (buffer, value, offset, isLE, mLen, nBytes) {
50806 var e, m, c;
50807 var eLen = nBytes * 8 - mLen - 1;
50808 var eMax = (1 << eLen) - 1;
50809 var eBias = eMax >> 1;
50810 var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0);
50811 var i = isLE ? 0 : (nBytes - 1);
50812 var d = isLE ? 1 : -1;
50813 var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
50814 value = Math.abs(value);
50815 if (isNaN(value) || value === Infinity) {
50816 m = isNaN(value) ? 1 : 0;
50817 e = eMax;
50818 } else {
50819 e = Math.floor(Math.log(value) / Math.LN2);
50820 if (value * (c = Math.pow(2, -e)) < 1) {
50821 e--;
50822 c *= 2;
50823 }
50824 if (e + eBias >= 1) {
50825 value += rt / c;
50826 } else {
50827 value += rt * Math.pow(2, 1 - eBias);
50828 }
50829 if (value * c >= 2) {
50830 e++;
50831 c /= 2;
50832 }
50833 if (e + eBias >= eMax) {
50834 m = 0;
50835 e = eMax;
50836 } else if (e + eBias >= 1) {
50837 m = (value * c - 1) * Math.pow(2, mLen);
50838 e = e + eBias;
50839 } else {
50840 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50841 e = 0;
50842 }
50843 }
50844 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50845 e = (e << mLen) | m;
50846 eLen += mLen;
50847 for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50848 buffer[offset + i - d] |= s * 128;
50849};
50850var index$2 = {
50851 read: read,
50852 write: write
50853};
50854
50855var index = Pbf;
50856function Pbf(buf) {
50857 this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50858 this.pos = 0;
50859 this.type = 0;
50860 this.length = this.buf.length;
50861}
50862Pbf.Varint = 0;
50863Pbf.Fixed64 = 1;
50864Pbf.Bytes = 2;
50865Pbf.Fixed32 = 5;
50866var SHIFT_LEFT_32 = (1 << 16) * (1 << 16);
50867var SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
50868Pbf.prototype = {
50869 destroy: function() {
50870 this.buf = null;
50871 },
50872 readFields: function(readField, result, end) {
50873 end = end || this.length;
50874 while (this.pos < end) {
50875 var val = this.readVarint(),
50876 tag = val >> 3,
50877 startPos = this.pos;
50878 this.type = val & 0x7;
50879 readField(tag, result, this);
50880 if (this.pos === startPos) this.skip(val);
50881 }
50882 return result;
50883 },
50884 readMessage: function(readField, result) {
50885 return this.readFields(readField, result, this.readVarint() + this.pos);
50886 },
50887 readFixed32: function() {
50888 var val = readUInt32(this.buf, this.pos);
50889 this.pos += 4;
50890 return val;
50891 },
50892 readSFixed32: function() {
50893 var val = readInt32(this.buf, this.pos);
50894 this.pos += 4;
50895 return val;
50896 },
50897 readFixed64: function() {
50898 var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50899 this.pos += 8;
50900 return val;
50901 },
50902 readSFixed64: function() {
50903 var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
50904 this.pos += 8;
50905 return val;
50906 },
50907 readFloat: function() {
50908 var val = index$2.read(this.buf, this.pos, true, 23, 4);
50909 this.pos += 4;
50910 return val;
50911 },
50912 readDouble: function() {
50913 var val = index$2.read(this.buf, this.pos, true, 52, 8);
50914 this.pos += 8;
50915 return val;
50916 },
50917 readVarint: function(isSigned) {
50918 var buf = this.buf,
50919 val, b;
50920 b = buf[this.pos++]; val = b & 0x7f; if (b < 0x80) return val;
50921 b = buf[this.pos++]; val |= (b & 0x7f) << 7; if (b < 0x80) return val;
50922 b = buf[this.pos++]; val |= (b & 0x7f) << 14; if (b < 0x80) return val;
50923 b = buf[this.pos++]; val |= (b & 0x7f) << 21; if (b < 0x80) return val;
50924 b = buf[this.pos]; val |= (b & 0x0f) << 28;
50925 return readVarintRemainder(val, isSigned, this);
50926 },
50927 readVarint64: function() {
50928 return this.readVarint(true);
50929 },
50930 readSVarint: function() {
50931 var num = this.readVarint();
50932 return num % 2 === 1 ? (num + 1) / -2 : num / 2;
50933 },
50934 readBoolean: function() {
50935 return Boolean(this.readVarint());
50936 },
50937 readString: function() {
50938 var end = this.readVarint() + this.pos,
50939 str = readUtf8(this.buf, this.pos, end);
50940 this.pos = end;
50941 return str;
50942 },
50943 readBytes: function() {
50944 var end = this.readVarint() + this.pos,
50945 buffer = this.buf.subarray(this.pos, end);
50946 this.pos = end;
50947 return buffer;
50948 },
50949 readPackedVarint: function(arr, isSigned) {
50950 var end = readPackedEnd(this);
50951 arr = arr || [];
50952 while (this.pos < end) arr.push(this.readVarint(isSigned));
50953 return arr;
50954 },
50955 readPackedSVarint: function(arr) {
50956 var end = readPackedEnd(this);
50957 arr = arr || [];
50958 while (this.pos < end) arr.push(this.readSVarint());
50959 return arr;
50960 },
50961 readPackedBoolean: function(arr) {
50962 var end = readPackedEnd(this);
50963 arr = arr || [];
50964 while (this.pos < end) arr.push(this.readBoolean());
50965 return arr;
50966 },
50967 readPackedFloat: function(arr) {
50968 var end = readPackedEnd(this);
50969 arr = arr || [];
50970 while (this.pos < end) arr.push(this.readFloat());
50971 return arr;
50972 },
50973 readPackedDouble: function(arr) {
50974 var end = readPackedEnd(this);
50975 arr = arr || [];
50976 while (this.pos < end) arr.push(this.readDouble());
50977 return arr;
50978 },
50979 readPackedFixed32: function(arr) {
50980 var end = readPackedEnd(this);
50981 arr = arr || [];
50982 while (this.pos < end) arr.push(this.readFixed32());
50983 return arr;
50984 },
50985 readPackedSFixed32: function(arr) {
50986 var end = readPackedEnd(this);
50987 arr = arr || [];
50988 while (this.pos < end) arr.push(this.readSFixed32());
50989 return arr;
50990 },
50991 readPackedFixed64: function(arr) {
50992 var end = readPackedEnd(this);
50993 arr = arr || [];
50994 while (this.pos < end) arr.push(this.readFixed64());
50995 return arr;
50996 },
50997 readPackedSFixed64: function(arr) {
50998 var end = readPackedEnd(this);
50999 arr = arr || [];
51000 while (this.pos < end) arr.push(this.readSFixed64());
51001 return arr;
51002 },
51003 skip: function(val) {
51004 var type = val & 0x7;
51005 if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {}
51006 else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;
51007 else if (type === Pbf.Fixed32) this.pos += 4;
51008 else if (type === Pbf.Fixed64) this.pos += 8;
51009 else throw new Error('Unimplemented type: ' + type);
51010 },
51011 writeTag: function(tag, type) {
51012 this.writeVarint((tag << 3) | type);
51013 },
51014 realloc: function(min) {
51015 var length = this.length || 16;
51016 while (length < this.pos + min) length *= 2;
51017 if (length !== this.length) {
51018 var buf = new Uint8Array(length);
51019 buf.set(this.buf);
51020 this.buf = buf;
51021 this.length = length;
51022 }
51023 },
51024 finish: function() {
51025 this.length = this.pos;
51026 this.pos = 0;
51027 return this.buf.subarray(0, this.length);
51028 },
51029 writeFixed32: function(val) {
51030 this.realloc(4);
51031 writeInt32(this.buf, val, this.pos);
51032 this.pos += 4;
51033 },
51034 writeSFixed32: function(val) {
51035 this.realloc(4);
51036 writeInt32(this.buf, val, this.pos);
51037 this.pos += 4;
51038 },
51039 writeFixed64: function(val) {
51040 this.realloc(8);
51041 writeInt32(this.buf, val & -1, this.pos);
51042 writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51043 this.pos += 8;
51044 },
51045 writeSFixed64: function(val) {
51046 this.realloc(8);
51047 writeInt32(this.buf, val & -1, this.pos);
51048 writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51049 this.pos += 8;
51050 },
51051 writeVarint: function(val) {
51052 val = +val || 0;
51053 if (val > 0xfffffff || val < 0) {
51054 writeBigVarint(val, this);
51055 return;
51056 }
51057 this.realloc(4);
51058 this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
51059 this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
51060 this.buf[this.pos++] = ((val >>>= 7) & 0x7f) | (val > 0x7f ? 0x80 : 0); if (val <= 0x7f) return;
51061 this.buf[this.pos++] = (val >>> 7) & 0x7f;
51062 },
51063 writeSVarint: function(val) {
51064 this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51065 },
51066 writeBoolean: function(val) {
51067 this.writeVarint(Boolean(val));
51068 },
51069 writeString: function(str) {
51070 str = String(str);
51071 this.realloc(str.length * 4);
51072 this.pos++;
51073 var startPos = this.pos;
51074 this.pos = writeUtf8(this.buf, str, this.pos);
51075 var len = this.pos - startPos;
51076 if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
51077 this.pos = startPos - 1;
51078 this.writeVarint(len);
51079 this.pos += len;
51080 },
51081 writeFloat: function(val) {
51082 this.realloc(4);
51083 index$2.write(this.buf, val, this.pos, true, 23, 4);
51084 this.pos += 4;
51085 },
51086 writeDouble: function(val) {
51087 this.realloc(8);
51088 index$2.write(this.buf, val, this.pos, true, 52, 8);
51089 this.pos += 8;
51090 },
51091 writeBytes: function(buffer) {
51092 var len = buffer.length;
51093 this.writeVarint(len);
51094 this.realloc(len);
51095 for (var i = 0; i < len; i++) this.buf[this.pos++] = buffer[i];
51096 },
51097 writeRawMessage: function(fn, obj) {
51098 this.pos++;
51099 var startPos = this.pos;
51100 fn(obj, this);
51101 var len = this.pos - startPos;
51102 if (len >= 0x80) makeRoomForExtraLength(startPos, len, this);
51103 this.pos = startPos - 1;
51104 this.writeVarint(len);
51105 this.pos += len;
51106 },
51107 writeMessage: function(tag, fn, obj) {
51108 this.writeTag(tag, Pbf.Bytes);
51109 this.writeRawMessage(fn, obj);
51110 },
51111 writePackedVarint: function(tag, arr) { this.writeMessage(tag, writePackedVarint, arr); },
51112 writePackedSVarint: function(tag, arr) { this.writeMessage(tag, writePackedSVarint, arr); },
51113 writePackedBoolean: function(tag, arr) { this.writeMessage(tag, writePackedBoolean, arr); },
51114 writePackedFloat: function(tag, arr) { this.writeMessage(tag, writePackedFloat, arr); },
51115 writePackedDouble: function(tag, arr) { this.writeMessage(tag, writePackedDouble, arr); },
51116 writePackedFixed32: function(tag, arr) { this.writeMessage(tag, writePackedFixed32, arr); },
51117 writePackedSFixed32: function(tag, arr) { this.writeMessage(tag, writePackedSFixed32, arr); },
51118 writePackedFixed64: function(tag, arr) { this.writeMessage(tag, writePackedFixed64, arr); },
51119 writePackedSFixed64: function(tag, arr) { this.writeMessage(tag, writePackedSFixed64, arr); },
51120 writeBytesField: function(tag, buffer) {
51121 this.writeTag(tag, Pbf.Bytes);
51122 this.writeBytes(buffer);
51123 },
51124 writeFixed32Field: function(tag, val) {
51125 this.writeTag(tag, Pbf.Fixed32);
51126 this.writeFixed32(val);
51127 },
51128 writeSFixed32Field: function(tag, val) {
51129 this.writeTag(tag, Pbf.Fixed32);
51130 this.writeSFixed32(val);
51131 },
51132 writeFixed64Field: function(tag, val) {
51133 this.writeTag(tag, Pbf.Fixed64);
51134 this.writeFixed64(val);
51135 },
51136 writeSFixed64Field: function(tag, val) {
51137 this.writeTag(tag, Pbf.Fixed64);
51138 this.writeSFixed64(val);
51139 },
51140 writeVarintField: function(tag, val) {
51141 this.writeTag(tag, Pbf.Varint);
51142 this.writeVarint(val);
51143 },
51144 writeSVarintField: function(tag, val) {
51145 this.writeTag(tag, Pbf.Varint);
51146 this.writeSVarint(val);
51147 },
51148 writeStringField: function(tag, str) {
51149 this.writeTag(tag, Pbf.Bytes);
51150 this.writeString(str);
51151 },
51152 writeFloatField: function(tag, val) {
51153 this.writeTag(tag, Pbf.Fixed32);
51154 this.writeFloat(val);
51155 },
51156 writeDoubleField: function(tag, val) {
51157 this.writeTag(tag, Pbf.Fixed64);
51158 this.writeDouble(val);
51159 },
51160 writeBooleanField: function(tag, val) {
51161 this.writeVarintField(tag, Boolean(val));
51162 }
51163};
51164function readVarintRemainder(l, s, p) {
51165 var buf = p.buf,
51166 h, b;
51167 b = buf[p.pos++]; h = (b & 0x70) >> 4; if (b < 0x80) return toNum(l, h, s);
51168 b = buf[p.pos++]; h |= (b & 0x7f) << 3; if (b < 0x80) return toNum(l, h, s);
51169 b = buf[p.pos++]; h |= (b & 0x7f) << 10; if (b < 0x80) return toNum(l, h, s);
51170 b = buf[p.pos++]; h |= (b & 0x7f) << 17; if (b < 0x80) return toNum(l, h, s);
51171 b = buf[p.pos++]; h |= (b & 0x7f) << 24; if (b < 0x80) return toNum(l, h, s);
51172 b = buf[p.pos++]; h |= (b & 0x01) << 31; if (b < 0x80) return toNum(l, h, s);
51173 throw new Error('Expected varint not more than 10 bytes');
51174}
51175function readPackedEnd(pbf) {
51176 return pbf.type === Pbf.Bytes ?
51177 pbf.readVarint() + pbf.pos : pbf.pos + 1;
51178}
51179function toNum(low, high, isSigned) {
51180 if (isSigned) {
51181 return high * 0x100000000 + (low >>> 0);
51182 }
51183 return ((high >>> 0) * 0x100000000) + (low >>> 0);
51184}
51185function writeBigVarint(val, pbf) {
51186 var low, high;
51187 if (val >= 0) {
51188 low = (val % 0x100000000) | 0;
51189 high = (val / 0x100000000) | 0;
51190 } else {
51191 low = ~(-val % 0x100000000);
51192 high = ~(-val / 0x100000000);
51193 if (low ^ 0xffffffff) {
51194 low = (low + 1) | 0;
51195 } else {
51196 low = 0;
51197 high = (high + 1) | 0;
51198 }
51199 }
51200 if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51201 throw new Error('Given varint doesn\'t fit into 10 bytes');
51202 }
51203 pbf.realloc(10);
51204 writeBigVarintLow(low, high, pbf);
51205 writeBigVarintHigh(high, pbf);
51206}
51207function writeBigVarintLow(low, high, pbf) {
51208 pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
51209 pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
51210 pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
51211 pbf.buf[pbf.pos++] = low & 0x7f | 0x80; low >>>= 7;
51212 pbf.buf[pbf.pos] = low & 0x7f;
51213}
51214function writeBigVarintHigh(high, pbf) {
51215 var lsb = (high & 0x07) << 4;
51216 pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0); if (!high) return;
51217 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
51218 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
51219 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
51220 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0); if (!high) return;
51221 pbf.buf[pbf.pos++] = high & 0x7f;
51222}
51223function makeRoomForExtraLength(startPos, len, pbf) {
51224 var extraLen =
51225 len <= 0x3fff ? 1 :
51226 len <= 0x1fffff ? 2 :
51227 len <= 0xfffffff ? 3 : Math.ceil(Math.log(len) / (Math.LN2 * 7));
51228 pbf.realloc(extraLen);
51229 for (var i = pbf.pos - 1; i >= startPos; i--) pbf.buf[i + extraLen] = pbf.buf[i];
51230}
51231function writePackedVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeVarint(arr[i]); }
51232function writePackedSVarint(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSVarint(arr[i]); }
51233function writePackedFloat(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFloat(arr[i]); }
51234function writePackedDouble(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeDouble(arr[i]); }
51235function writePackedBoolean(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeBoolean(arr[i]); }
51236function writePackedFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed32(arr[i]); }
51237function writePackedSFixed32(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed32(arr[i]); }
51238function writePackedFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeFixed64(arr[i]); }
51239function writePackedSFixed64(arr, pbf) { for (var i = 0; i < arr.length; i++) pbf.writeSFixed64(arr[i]); }
51240function readUInt32(buf, pos) {
51241 return ((buf[pos]) |
51242 (buf[pos + 1] << 8) |
51243 (buf[pos + 2] << 16)) +
51244 (buf[pos + 3] * 0x1000000);
51245}
51246function writeInt32(buf, val, pos) {
51247 buf[pos] = val;
51248 buf[pos + 1] = (val >>> 8);
51249 buf[pos + 2] = (val >>> 16);
51250 buf[pos + 3] = (val >>> 24);
51251}
51252function readInt32(buf, pos) {
51253 return ((buf[pos]) |
51254 (buf[pos + 1] << 8) |
51255 (buf[pos + 2] << 16)) +
51256 (buf[pos + 3] << 24);
51257}
51258function readUtf8(buf, pos, end) {
51259 var str = '';
51260 var i = pos;
51261 while (i < end) {
51262 var b0 = buf[i];
51263 var c = null;
51264 var bytesPerSequence =
51265 b0 > 0xEF ? 4 :
51266 b0 > 0xDF ? 3 :
51267 b0 > 0xBF ? 2 : 1;
51268 if (i + bytesPerSequence > end) break;
51269 var b1, b2, b3;
51270 if (bytesPerSequence === 1) {
51271 if (b0 < 0x80) {
51272 c = b0;
51273 }
51274 } else if (bytesPerSequence === 2) {
51275 b1 = buf[i + 1];
51276 if ((b1 & 0xC0) === 0x80) {
51277 c = (b0 & 0x1F) << 0x6 | (b1 & 0x3F);
51278 if (c <= 0x7F) {
51279 c = null;
51280 }
51281 }
51282 } else if (bytesPerSequence === 3) {
51283 b1 = buf[i + 1];
51284 b2 = buf[i + 2];
51285 if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51286 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | (b2 & 0x3F);
51287 if (c <= 0x7FF || (c >= 0xD800 && c <= 0xDFFF)) {
51288 c = null;
51289 }
51290 }
51291 } else if (bytesPerSequence === 4) {
51292 b1 = buf[i + 1];
51293 b2 = buf[i + 2];
51294 b3 = buf[i + 3];
51295 if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51296 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | (b3 & 0x3F);
51297 if (c <= 0xFFFF || c >= 0x110000) {
51298 c = null;
51299 }
51300 }
51301 }
51302 if (c === null) {
51303 c = 0xFFFD;
51304 bytesPerSequence = 1;
51305 } else if (c > 0xFFFF) {
51306 c -= 0x10000;
51307 str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51308 c = 0xDC00 | c & 0x3FF;
51309 }
51310 str += String.fromCharCode(c);
51311 i += bytesPerSequence;
51312 }
51313 return str;
51314}
51315function writeUtf8(buf, str, pos) {
51316 for (var i = 0, c, lead; i < str.length; i++) {
51317 c = str.charCodeAt(i);
51318 if (c > 0xD7FF && c < 0xE000) {
51319 if (lead) {
51320 if (c < 0xDC00) {
51321 buf[pos++] = 0xEF;
51322 buf[pos++] = 0xBF;
51323 buf[pos++] = 0xBD;
51324 lead = c;
51325 continue;
51326 } else {
51327 c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51328 lead = null;
51329 }
51330 } else {
51331 if (c > 0xDBFF || (i + 1 === str.length)) {
51332 buf[pos++] = 0xEF;
51333 buf[pos++] = 0xBF;
51334 buf[pos++] = 0xBD;
51335 } else {
51336 lead = c;
51337 }
51338 continue;
51339 }
51340 } else if (lead) {
51341 buf[pos++] = 0xEF;
51342 buf[pos++] = 0xBF;
51343 buf[pos++] = 0xBD;
51344 lead = null;
51345 }
51346 if (c < 0x80) {
51347 buf[pos++] = c;
51348 } else {
51349 if (c < 0x800) {
51350 buf[pos++] = c >> 0x6 | 0xC0;
51351 } else {
51352 if (c < 0x10000) {
51353 buf[pos++] = c >> 0xC | 0xE0;
51354 } else {
51355 buf[pos++] = c >> 0x12 | 0xF0;
51356 buf[pos++] = c >> 0xC & 0x3F | 0x80;
51357 }
51358 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51359 }
51360 buf[pos++] = c & 0x3F | 0x80;
51361 }
51362 }
51363 return pos;
51364}
51365
51366exports['default'] = index;
51367
51368}((this.PBF = this.PBF || {})));}).call(ol.ext);
51369ol.ext.PBF = ol.ext.PBF.default;
51370
51371
51372/**
51373 * @fileoverview
51374 * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, unusedLocalVariables, uselessCode, visibility}
51375 */
51376goog.provide('ol.ext.vectortile.VectorTile');
51377
51378/** @typedef {function(*)} */
51379ol.ext.vectortile.VectorTile = function() {};
51380
51381(function() {(function (exports) {
51382'use strict';
51383
51384var index$2 = Point;
51385function Point(x, y) {
51386 this.x = x;
51387 this.y = y;
51388}
51389Point.prototype = {
51390 clone: function() { return new Point(this.x, this.y); },
51391 add: function(p) { return this.clone()._add(p); },
51392 sub: function(p) { return this.clone()._sub(p); },
51393 multByPoint: function(p) { return this.clone()._multByPoint(p); },
51394 divByPoint: function(p) { return this.clone()._divByPoint(p); },
51395 mult: function(k) { return this.clone()._mult(k); },
51396 div: function(k) { return this.clone()._div(k); },
51397 rotate: function(a) { return this.clone()._rotate(a); },
51398 rotateAround: function(a,p) { return this.clone()._rotateAround(a,p); },
51399 matMult: function(m) { return this.clone()._matMult(m); },
51400 unit: function() { return this.clone()._unit(); },
51401 perp: function() { return this.clone()._perp(); },
51402 round: function() { return this.clone()._round(); },
51403 mag: function() {
51404 return Math.sqrt(this.x * this.x + this.y * this.y);
51405 },
51406 equals: function(other) {
51407 return this.x === other.x &&
51408 this.y === other.y;
51409 },
51410 dist: function(p) {
51411 return Math.sqrt(this.distSqr(p));
51412 },
51413 distSqr: function(p) {
51414 var dx = p.x - this.x,
51415 dy = p.y - this.y;
51416 return dx * dx + dy * dy;
51417 },
51418 angle: function() {
51419 return Math.atan2(this.y, this.x);
51420 },
51421 angleTo: function(b) {
51422 return Math.atan2(this.y - b.y, this.x - b.x);
51423 },
51424 angleWith: function(b) {
51425 return this.angleWithSep(b.x, b.y);
51426 },
51427 angleWithSep: function(x, y) {
51428 return Math.atan2(
51429 this.x * y - this.y * x,
51430 this.x * x + this.y * y);
51431 },
51432 _matMult: function(m) {
51433 var x = m[0] * this.x + m[1] * this.y,
51434 y = m[2] * this.x + m[3] * this.y;
51435 this.x = x;
51436 this.y = y;
51437 return this;
51438 },
51439 _add: function(p) {
51440 this.x += p.x;
51441 this.y += p.y;
51442 return this;
51443 },
51444 _sub: function(p) {
51445 this.x -= p.x;
51446 this.y -= p.y;
51447 return this;
51448 },
51449 _mult: function(k) {
51450 this.x *= k;
51451 this.y *= k;
51452 return this;
51453 },
51454 _div: function(k) {
51455 this.x /= k;
51456 this.y /= k;
51457 return this;
51458 },
51459 _multByPoint: function(p) {
51460 this.x *= p.x;
51461 this.y *= p.y;
51462 return this;
51463 },
51464 _divByPoint: function(p) {
51465 this.x /= p.x;
51466 this.y /= p.y;
51467 return this;
51468 },
51469 _unit: function() {
51470 this._div(this.mag());
51471 return this;
51472 },
51473 _perp: function() {
51474 var y = this.y;
51475 this.y = this.x;
51476 this.x = -y;
51477 return this;
51478 },
51479 _rotate: function(angle) {
51480 var cos = Math.cos(angle),
51481 sin = Math.sin(angle),
51482 x = cos * this.x - sin * this.y,
51483 y = sin * this.x + cos * this.y;
51484 this.x = x;
51485 this.y = y;
51486 return this;
51487 },
51488 _rotateAround: function(angle, p) {
51489 var cos = Math.cos(angle),
51490 sin = Math.sin(angle),
51491 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51492 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51493 this.x = x;
51494 this.y = y;
51495 return this;
51496 },
51497 _round: function() {
51498 this.x = Math.round(this.x);
51499 this.y = Math.round(this.y);
51500 return this;
51501 }
51502};
51503Point.convert = function (a) {
51504 if (a instanceof Point) {
51505 return a;
51506 }
51507 if (Array.isArray(a)) {
51508 return new Point(a[0], a[1]);
51509 }
51510 return a;
51511};
51512
51513var vectortilefeature = VectorTileFeature$1;
51514function VectorTileFeature$1(pbf, end, extent, keys, values) {
51515 this.properties = {};
51516 this.extent = extent;
51517 this.type = 0;
51518 this._pbf = pbf;
51519 this._geometry = -1;
51520 this._keys = keys;
51521 this._values = values;
51522 pbf.readFields(readFeature, this, end);
51523}
51524function readFeature(tag, feature, pbf) {
51525 if (tag == 1) feature.id = pbf.readVarint();
51526 else if (tag == 2) readTag(pbf, feature);
51527 else if (tag == 3) feature.type = pbf.readVarint();
51528 else if (tag == 4) feature._geometry = pbf.pos;
51529}
51530function readTag(pbf, feature) {
51531 var end = pbf.readVarint() + pbf.pos;
51532 while (pbf.pos < end) {
51533 var key = feature._keys[pbf.readVarint()],
51534 value = feature._values[pbf.readVarint()];
51535 feature.properties[key] = value;
51536 }
51537}
51538VectorTileFeature$1.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
51539VectorTileFeature$1.prototype.loadGeometry = function() {
51540 var pbf = this._pbf;
51541 pbf.pos = this._geometry;
51542 var end = pbf.readVarint() + pbf.pos,
51543 cmd = 1,
51544 length = 0,
51545 x = 0,
51546 y = 0,
51547 lines = [],
51548 line;
51549 while (pbf.pos < end) {
51550 if (!length) {
51551 var cmdLen = pbf.readVarint();
51552 cmd = cmdLen & 0x7;
51553 length = cmdLen >> 3;
51554 }
51555 length--;
51556 if (cmd === 1 || cmd === 2) {
51557 x += pbf.readSVarint();
51558 y += pbf.readSVarint();
51559 if (cmd === 1) {
51560 if (line) lines.push(line);
51561 line = [];
51562 }
51563 line.push(new index$2(x, y));
51564 } else if (cmd === 7) {
51565 if (line) {
51566 line.push(line[0].clone());
51567 }
51568 } else {
51569 throw new Error('unknown command ' + cmd);
51570 }
51571 }
51572 if (line) lines.push(line);
51573 return lines;
51574};
51575VectorTileFeature$1.prototype.bbox = function() {
51576 var pbf = this._pbf;
51577 pbf.pos = this._geometry;
51578 var end = pbf.readVarint() + pbf.pos,
51579 cmd = 1,
51580 length = 0,
51581 x = 0,
51582 y = 0,
51583 x1 = Infinity,
51584 x2 = -Infinity,
51585 y1 = Infinity,
51586 y2 = -Infinity;
51587 while (pbf.pos < end) {
51588 if (!length) {
51589 var cmdLen = pbf.readVarint();
51590 cmd = cmdLen & 0x7;
51591 length = cmdLen >> 3;
51592 }
51593 length--;
51594 if (cmd === 1 || cmd === 2) {
51595 x += pbf.readSVarint();
51596 y += pbf.readSVarint();
51597 if (x < x1) x1 = x;
51598 if (x > x2) x2 = x;
51599 if (y < y1) y1 = y;
51600 if (y > y2) y2 = y;
51601 } else if (cmd !== 7) {
51602 throw new Error('unknown command ' + cmd);
51603 }
51604 }
51605 return [x1, y1, x2, y2];
51606};
51607VectorTileFeature$1.prototype.toGeoJSON = function(x, y, z) {
51608 var size = this.extent * Math.pow(2, z),
51609 x0 = this.extent * x,
51610 y0 = this.extent * y,
51611 coords = this.loadGeometry(),
51612 type = VectorTileFeature$1.types[this.type],
51613 i, j;
51614 function project(line) {
51615 for (var j = 0; j < line.length; j++) {
51616 var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
51617 line[j] = [
51618 (p.x + x0) * 360 / size - 180,
51619 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
51620 ];
51621 }
51622 }
51623 switch (this.type) {
51624 case 1:
51625 var points = [];
51626 for (i = 0; i < coords.length; i++) {
51627 points[i] = coords[i][0];
51628 }
51629 coords = points;
51630 project(coords);
51631 break;
51632 case 2:
51633 for (i = 0; i < coords.length; i++) {
51634 project(coords[i]);
51635 }
51636 break;
51637 case 3:
51638 coords = classifyRings(coords);
51639 for (i = 0; i < coords.length; i++) {
51640 for (j = 0; j < coords[i].length; j++) {
51641 project(coords[i][j]);
51642 }
51643 }
51644 break;
51645 }
51646 if (coords.length === 1) {
51647 coords = coords[0];
51648 } else {
51649 type = 'Multi' + type;
51650 }
51651 var result = {
51652 type: "Feature",
51653 geometry: {
51654 type: type,
51655 coordinates: coords
51656 },
51657 properties: this.properties
51658 };
51659 if ('id' in this) {
51660 result.id = this.id;
51661 }
51662 return result;
51663};
51664function classifyRings(rings) {
51665 var len = rings.length;
51666 if (len <= 1) return [rings];
51667 var polygons = [],
51668 polygon,
51669 ccw;
51670 for (var i = 0; i < len; i++) {
51671 var area = signedArea(rings[i]);
51672 if (area === 0) continue;
51673 if (ccw === undefined) ccw = area < 0;
51674 if (ccw === area < 0) {
51675 if (polygon) polygons.push(polygon);
51676 polygon = [rings[i]];
51677 } else {
51678 polygon.push(rings[i]);
51679 }
51680 }
51681 if (polygon) polygons.push(polygon);
51682 return polygons;
51683}
51684function signedArea(ring) {
51685 var sum = 0;
51686 for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
51687 p1 = ring[i];
51688 p2 = ring[j];
51689 sum += (p2.x - p1.x) * (p1.y + p2.y);
51690 }
51691 return sum;
51692}
51693
51694var vectortilelayer = VectorTileLayer$1;
51695function VectorTileLayer$1(pbf, end) {
51696 this.version = 1;
51697 this.name = null;
51698 this.extent = 4096;
51699 this.length = 0;
51700 this._pbf = pbf;
51701 this._keys = [];
51702 this._values = [];
51703 this._features = [];
51704 pbf.readFields(readLayer, this, end);
51705 this.length = this._features.length;
51706}
51707function readLayer(tag, layer, pbf) {
51708 if (tag === 15) layer.version = pbf.readVarint();
51709 else if (tag === 1) layer.name = pbf.readString();
51710 else if (tag === 5) layer.extent = pbf.readVarint();
51711 else if (tag === 2) layer._features.push(pbf.pos);
51712 else if (tag === 3) layer._keys.push(pbf.readString());
51713 else if (tag === 4) layer._values.push(readValueMessage(pbf));
51714}
51715function readValueMessage(pbf) {
51716 var value = null,
51717 end = pbf.readVarint() + pbf.pos;
51718 while (pbf.pos < end) {
51719 var tag = pbf.readVarint() >> 3;
51720 value = tag === 1 ? pbf.readString() :
51721 tag === 2 ? pbf.readFloat() :
51722 tag === 3 ? pbf.readDouble() :
51723 tag === 4 ? pbf.readVarint64() :
51724 tag === 5 ? pbf.readVarint() :
51725 tag === 6 ? pbf.readSVarint() :
51726 tag === 7 ? pbf.readBoolean() : null;
51727 }
51728 return value;
51729}
51730VectorTileLayer$1.prototype.feature = function(i) {
51731 if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
51732 this._pbf.pos = this._features[i];
51733 var end = this._pbf.readVarint() + this._pbf.pos;
51734 return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
51735};
51736
51737var vectortile = VectorTile$1;
51738function VectorTile$1(pbf, end) {
51739 this.layers = pbf.readFields(readTile, {}, end);
51740}
51741function readTile(tag, layers, pbf) {
51742 if (tag === 3) {
51743 var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
51744 if (layer.length) layers[layer.name] = layer;
51745 }
51746}
51747
51748var VectorTile = vectortile;
51749var VectorTileFeature = vectortilefeature;
51750var VectorTileLayer = vectortilelayer;
51751var index = {
51752 VectorTile: VectorTile,
51753 VectorTileFeature: VectorTileFeature,
51754 VectorTileLayer: VectorTileLayer
51755};
51756
51757exports['default'] = index;
51758exports.VectorTile = VectorTile;
51759exports.VectorTileFeature = VectorTileFeature;
51760exports.VectorTileLayer = VectorTileLayer;
51761
51762}((this.vectortile = this.vectortile || {})));}).call(ol.ext);
51763
51764goog.provide('ol.render.Feature');
51765
51766goog.require('ol');
51767goog.require('ol.extent');
51768goog.require('ol.geom.GeometryType');
51769
51770
51771/**
51772 * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like
51773 * structure, optimized for rendering and styling. Geometry access through the
51774 * API is limited to getting the type and extent of the geometry.
51775 *
51776 * @constructor
51777 * @param {ol.geom.GeometryType} type Geometry type.
51778 * @param {Array.<number>} flatCoordinates Flat coordinates. These always need
51779 * to be right-handed for polygons.
51780 * @param {Array.<number>|Array.<Array.<number>>} ends Ends or Endss.
51781 * @param {Object.<string, *>} properties Properties.
51782 * @param {number|string|undefined} id Feature id.
51783 */
51784ol.render.Feature = function(type, flatCoordinates, ends, properties, id) {
51785 /**
51786 * @private
51787 * @type {ol.Extent|undefined}
51788 */
51789 this.extent_;
51790
51791 /**
51792 * @private
51793 * @type {number|string|undefined}
51794 */
51795 this.id_ = id;
51796
51797 /**
51798 * @private
51799 * @type {ol.geom.GeometryType}
51800 */
51801 this.type_ = type;
51802
51803 /**
51804 * @private
51805 * @type {Array.<number>}
51806 */
51807 this.flatCoordinates_ = flatCoordinates;
51808
51809 /**
51810 * @private
51811 * @type {Array.<number>|Array.<Array.<number>>}
51812 */
51813 this.ends_ = ends;
51814
51815 /**
51816 * @private
51817 * @type {Object.<string, *>}
51818 */
51819 this.properties_ = properties;
51820};
51821
51822
51823/**
51824 * Get a feature property by its key.
51825 * @param {string} key Key
51826 * @return {*} Value for the requested key.
51827 * @api
51828 */
51829ol.render.Feature.prototype.get = function(key) {
51830 return this.properties_[key];
51831};
51832
51833
51834/**
51835 * @return {Array.<number>|Array.<Array.<number>>} Ends or endss.
51836 */
51837ol.render.Feature.prototype.getEnds = function() {
51838 return this.ends_;
51839};
51840
51841
51842/**
51843 * Get the extent of this feature's geometry.
51844 * @return {ol.Extent} Extent.
51845 * @api
51846 */
51847ol.render.Feature.prototype.getExtent = function() {
51848 if (!this.extent_) {
51849 this.extent_ = this.type_ === ol.geom.GeometryType.POINT ?
51850 ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) :
51851 ol.extent.createOrUpdateFromFlatCoordinates(
51852 this.flatCoordinates_, 0, this.flatCoordinates_.length, 2);
51853
51854 }
51855 return this.extent_;
51856};
51857
51858/**
51859 * Get the feature identifier. This is a stable identifier for the feature and
51860 * is set when reading data from a remote source.
51861 * @return {number|string|undefined} Id.
51862 * @api
51863 */
51864ol.render.Feature.prototype.getId = function() {
51865 return this.id_;
51866};
51867
51868
51869/**
51870 * @return {Array.<number>} Flat coordinates.
51871 */
51872ol.render.Feature.prototype.getOrientedFlatCoordinates = function() {
51873 return this.flatCoordinates_;
51874};
51875
51876
51877/**
51878 * @return {Array.<number>} Flat coordinates.
51879 */
51880ol.render.Feature.prototype.getFlatCoordinates =
51881 ol.render.Feature.prototype.getOrientedFlatCoordinates;
51882
51883
51884/**
51885 * For API compatibility with {@link ol.Feature}, this method is useful when
51886 * determining the geometry type in style function (see {@link #getType}).
51887 * @return {ol.render.Feature} Feature.
51888 * @api
51889 */
51890ol.render.Feature.prototype.getGeometry = function() {
51891 return this;
51892};
51893
51894
51895/**
51896 * Get the feature properties.
51897 * @return {Object.<string, *>} Feature properties.
51898 * @api
51899 */
51900ol.render.Feature.prototype.getProperties = function() {
51901 return this.properties_;
51902};
51903
51904
51905/**
51906 * Get the feature for working with its geometry.
51907 * @return {ol.render.Feature} Feature.
51908 */
51909ol.render.Feature.prototype.getSimplifiedGeometry =
51910 ol.render.Feature.prototype.getGeometry;
51911
51912
51913/**
51914 * @return {number} Stride.
51915 */
51916ol.render.Feature.prototype.getStride = function() {
51917 return 2;
51918};
51919
51920
51921/**
51922 * @return {undefined}
51923 */
51924ol.render.Feature.prototype.getStyleFunction = ol.nullFunction;
51925
51926
51927/**
51928 * Get the type of this feature's geometry.
51929 * @return {ol.geom.GeometryType} Geometry type.
51930 * @api
51931 */
51932ol.render.Feature.prototype.getType = function() {
51933 return this.type_;
51934};
51935
51936//FIXME Implement projection handling
51937
51938goog.provide('ol.format.MVT');
51939
51940goog.require('ol');
51941goog.require('ol.ext.PBF');
51942goog.require('ol.ext.vectortile.VectorTile');
51943goog.require('ol.format.Feature');
51944goog.require('ol.format.FormatType');
51945goog.require('ol.geom.GeometryLayout');
51946goog.require('ol.geom.GeometryType');
51947goog.require('ol.geom.LineString');
51948goog.require('ol.geom.MultiLineString');
51949goog.require('ol.geom.MultiPoint');
51950goog.require('ol.geom.Point');
51951goog.require('ol.geom.Polygon');
51952goog.require('ol.proj.Projection');
51953goog.require('ol.proj.Units');
51954goog.require('ol.render.Feature');
51955
51956
51957/**
51958 * @classdesc
51959 * Feature format for reading data in the Mapbox MVT format.
51960 *
51961 * @constructor
51962 * @extends {ol.format.Feature}
51963 * @param {olx.format.MVTOptions=} opt_options Options.
51964 * @api
51965 */
51966ol.format.MVT = function(opt_options) {
51967
51968 ol.format.Feature.call(this);
51969
51970 var options = opt_options ? opt_options : {};
51971
51972 /**
51973 * @type {ol.proj.Projection}
51974 */
51975 this.defaultDataProjection = new ol.proj.Projection({
51976 code: '',
51977 units: ol.proj.Units.TILE_PIXELS
51978 });
51979
51980 /**
51981 * @private
51982 * @type {function((ol.geom.Geometry|Object.<string,*>)=)|
51983 * function(ol.geom.GeometryType,Array.<number>,
51984 * (Array.<number>|Array.<Array.<number>>),Object.<string,*>,number)}
51985 */
51986 this.featureClass_ = options.featureClass ?
51987 options.featureClass : ol.render.Feature;
51988
51989 /**
51990 * @private
51991 * @type {string|undefined}
51992 */
51993 this.geometryName_ = options.geometryName;
51994
51995 /**
51996 * @private
51997 * @type {string}
51998 */
51999 this.layerName_ = options.layerName ? options.layerName : 'layer';
52000
52001 /**
52002 * @private
52003 * @type {Array.<string>}
52004 */
52005 this.layers_ = options.layers ? options.layers : null;
52006
52007 /**
52008 * @private
52009 * @type {ol.Extent}
52010 */
52011 this.extent_ = null;
52012
52013};
52014ol.inherits(ol.format.MVT, ol.format.Feature);
52015
52016
52017/**
52018 * @inheritDoc
52019 * @api
52020 */
52021ol.format.MVT.prototype.getLastExtent = function() {
52022 return this.extent_;
52023};
52024
52025
52026/**
52027 * @inheritDoc
52028 */
52029ol.format.MVT.prototype.getType = function() {
52030 return ol.format.FormatType.ARRAY_BUFFER;
52031};
52032
52033
52034/**
52035 * @private
52036 * @param {Object} rawFeature Raw Mapbox feature.
52037 * @param {string} layer Layer.
52038 * @param {olx.format.ReadOptions=} opt_options Read options.
52039 * @return {ol.Feature} Feature.
52040 */
52041ol.format.MVT.prototype.readFeature_ = function(
52042 rawFeature, layer, opt_options) {
52043 var feature = new this.featureClass_();
52044 var id = rawFeature.id;
52045 var values = rawFeature.properties;
52046 values[this.layerName_] = layer;
52047 if (this.geometryName_) {
52048 feature.setGeometryName(this.geometryName_);
52049 }
52050 var geometry = ol.format.Feature.transformWithOptions(
52051 ol.format.MVT.readGeometry_(rawFeature), false,
52052 this.adaptOptions(opt_options));
52053 feature.setGeometry(geometry);
52054 feature.setId(id);
52055 feature.setProperties(values);
52056 return feature;
52057};
52058
52059
52060/**
52061 * @private
52062 * @param {Object} rawFeature Raw Mapbox feature.
52063 * @param {string} layer Layer.
52064 * @return {ol.render.Feature} Feature.
52065 */
52066ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) {
52067 var coords = rawFeature.loadGeometry();
52068 var ends = [];
52069 var flatCoordinates = [];
52070 ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);
52071
52072 var type = rawFeature.type;
52073 /** @type {ol.geom.GeometryType} */
52074 var geometryType;
52075 if (type === 1) {
52076 geometryType = coords.length === 1 ?
52077 ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT;
52078 } else if (type === 2) {
52079 if (coords.length === 1) {
52080 geometryType = ol.geom.GeometryType.LINE_STRING;
52081 } else {
52082 geometryType = ol.geom.GeometryType.MULTI_LINE_STRING;
52083 }
52084 } else if (type === 3) {
52085 geometryType = ol.geom.GeometryType.POLYGON;
52086 }
52087
52088 var values = rawFeature.properties;
52089 values[this.layerName_] = layer;
52090 var id = rawFeature.id;
52091
52092 return new this.featureClass_(geometryType, flatCoordinates, ends, values, id);
52093};
52094
52095
52096/**
52097 * @inheritDoc
52098 * @api
52099 */
52100ol.format.MVT.prototype.readFeatures = function(source, opt_options) {
52101 var layers = this.layers_;
52102
52103 var pbf = new ol.ext.PBF(/** @type {ArrayBuffer} */ (source));
52104 var tile = new ol.ext.vectortile.VectorTile(pbf);
52105 var features = [];
52106 var featureClass = this.featureClass_;
52107 var layer, feature;
52108 for (var name in tile.layers) {
52109 if (layers && layers.indexOf(name) == -1) {
52110 continue;
52111 }
52112 layer = tile.layers[name];
52113
52114 var rawFeature;
52115 for (var i = 0, ii = layer.length; i < ii; ++i) {
52116 rawFeature = layer.feature(i);
52117 if (featureClass === ol.render.Feature) {
52118 feature = this.readRenderFeature_(rawFeature, name);
52119 } else {
52120 feature = this.readFeature_(rawFeature, name, opt_options);
52121 }
52122 features.push(feature);
52123 }
52124 this.extent_ = layer ? [0, 0, layer.extent, layer.extent] : null;
52125 }
52126
52127 return features;
52128};
52129
52130
52131/**
52132 * @inheritDoc
52133 * @api
52134 */
52135ol.format.MVT.prototype.readProjection = function(source) {
52136 return this.defaultDataProjection;
52137};
52138
52139
52140/**
52141 * Sets the layers that features will be read from.
52142 * @param {Array.<string>} layers Layers.
52143 * @api
52144 */
52145ol.format.MVT.prototype.setLayers = function(layers) {
52146 this.layers_ = layers;
52147};
52148
52149
52150/**
52151 * @private
52152 * @param {Object} coords Raw feature coordinates.
52153 * @param {Array.<number>} flatCoordinates Flat coordinates to be populated by
52154 * this function.
52155 * @param {Array.<number>} ends Ends to be populated by this function.
52156 */
52157ol.format.MVT.calculateFlatCoordinates_ = function(
52158 coords, flatCoordinates, ends) {
52159 var end = 0;
52160 for (var i = 0, ii = coords.length; i < ii; ++i) {
52161 var line = coords[i];
52162 var j, jj;
52163 for (j = 0, jj = line.length; j < jj; ++j) {
52164 var coord = line[j];
52165 // Non-tilespace coords can be calculated here when a TileGrid and
52166 // TileCoord are known.
52167 flatCoordinates.push(coord.x, coord.y);
52168 }
52169 end += 2 * j;
52170 ends.push(end);
52171 }
52172};
52173
52174
52175/**
52176 * @private
52177 * @param {Object} rawFeature Raw Mapbox feature.
52178 * @return {ol.geom.Geometry} Geometry.
52179 */
52180ol.format.MVT.readGeometry_ = function(rawFeature) {
52181 var type = rawFeature.type;
52182 if (type === 0) {
52183 return null;
52184 }
52185
52186 var coords = rawFeature.loadGeometry();
52187 var ends = [];
52188 var flatCoordinates = [];
52189 ol.format.MVT.calculateFlatCoordinates_(coords, flatCoordinates, ends);
52190
52191 var geom;
52192 if (type === 1) {
52193 geom = coords.length === 1 ?
52194 new ol.geom.Point(null) : new ol.geom.MultiPoint(null);
52195 } else if (type === 2) {
52196 if (coords.length === 1) {
52197 geom = new ol.geom.LineString(null);
52198 } else {
52199 geom = new ol.geom.MultiLineString(null);
52200 }
52201 } else if (type === 3) {
52202 geom = new ol.geom.Polygon(null);
52203 }
52204
52205 geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
52206 ends);
52207
52208 return geom;
52209};
52210
52211
52212/**
52213 * Not implemented.
52214 * @override
52215 */
52216ol.format.MVT.prototype.readFeature = function() {};
52217
52218
52219/**
52220 * Not implemented.
52221 * @override
52222 */
52223ol.format.MVT.prototype.readGeometry = function() {};
52224
52225
52226/**
52227 * Not implemented.
52228 * @override
52229 */
52230ol.format.MVT.prototype.writeFeature = function() {};
52231
52232
52233/**
52234 * Not implemented.
52235 * @override
52236 */
52237ol.format.MVT.prototype.writeGeometry = function() {};
52238
52239
52240/**
52241 * Not implemented.
52242 * @override
52243 */
52244ol.format.MVT.prototype.writeFeatures = function() {};
52245
52246// FIXME add typedef for stack state objects
52247goog.provide('ol.format.OSMXML');
52248
52249goog.require('ol');
52250goog.require('ol.array');
52251goog.require('ol.Feature');
52252goog.require('ol.format.Feature');
52253goog.require('ol.format.XMLFeature');
52254goog.require('ol.geom.GeometryLayout');
52255goog.require('ol.geom.LineString');
52256goog.require('ol.geom.Point');
52257goog.require('ol.geom.Polygon');
52258goog.require('ol.obj');
52259goog.require('ol.proj');
52260goog.require('ol.xml');
52261
52262
52263/**
52264 * @classdesc
52265 * Feature format for reading data in the
52266 * [OSMXML format](http://wiki.openstreetmap.org/wiki/OSM_XML).
52267 *
52268 * @constructor
52269 * @extends {ol.format.XMLFeature}
52270 * @api
52271 */
52272ol.format.OSMXML = function() {
52273 ol.format.XMLFeature.call(this);
52274
52275 /**
52276 * @inheritDoc
52277 */
52278 this.defaultDataProjection = ol.proj.get('EPSG:4326');
52279};
52280ol.inherits(ol.format.OSMXML, ol.format.XMLFeature);
52281
52282
52283/**
52284 * @param {Node} node Node.
52285 * @param {Array.<*>} objectStack Object stack.
52286 * @private
52287 */
52288ol.format.OSMXML.readNode_ = function(node, objectStack) {
52289 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
52290 var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
52291 var id = node.getAttribute('id');
52292 /** @type {ol.Coordinate} */
52293 var coordinates = [
52294 parseFloat(node.getAttribute('lon')),
52295 parseFloat(node.getAttribute('lat'))
52296 ];
52297 state.nodes[id] = coordinates;
52298
52299 var values = ol.xml.pushParseAndPop({
52300 tags: {}
52301 }, ol.format.OSMXML.NODE_PARSERS_, node, objectStack);
52302 if (!ol.obj.isEmpty(values.tags)) {
52303 var geometry = new ol.geom.Point(coordinates);
52304 ol.format.Feature.transformWithOptions(geometry, false, options);
52305 var feature = new ol.Feature(geometry);
52306 feature.setId(id);
52307 feature.setProperties(values.tags);
52308 state.features.push(feature);
52309 }
52310};
52311
52312
52313/**
52314 * @param {Node} node Node.
52315 * @param {Array.<*>} objectStack Object stack.
52316 * @private
52317 */
52318ol.format.OSMXML.readWay_ = function(node, objectStack) {
52319 var options = /** @type {olx.format.ReadOptions} */ (objectStack[0]);
52320 var id = node.getAttribute('id');
52321 var values = ol.xml.pushParseAndPop({
52322 ndrefs: [],
52323 tags: {}
52324 }, ol.format.OSMXML.WAY_PARSERS_, node, objectStack);
52325 var state = /** @type {Object} */ (objectStack[objectStack.length - 1]);
52326 /** @type {Array.<number>} */
52327 var flatCoordinates = [];
52328 for (var i = 0, ii = values.ndrefs.length; i < ii; i++) {
52329 var point = state.nodes[values.ndrefs[i]];
52330 ol.array.extend(flatCoordinates, point);
52331 }
52332 var geometry;
52333 if (values.ndrefs[0] == values.ndrefs[values.ndrefs.length - 1]) {
52334 // closed way
52335 geometry = new ol.geom.Polygon(null);
52336 geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
52337 [flatCoordinates.length]);
52338 } else {
52339 geometry = new ol.geom.LineString(null);
52340 geometry.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
52341 }
52342 ol.format.Feature.transformWithOptions(geometry, false, options);
52343 var feature = new ol.Feature(geometry);
52344 feature.setId(id);
52345 feature.setProperties(values.tags);
52346 state.features.push(feature);
52347};
52348
52349
52350/**
52351 * @param {Node} node Node.
52352 * @param {Array.<*>} objectStack Object stack.
52353 * @private
52354 */
52355ol.format.OSMXML.readNd_ = function(node, objectStack) {
52356 var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
52357 values.ndrefs.push(node.getAttribute('ref'));
52358};
52359
52360
52361/**
52362 * @param {Node} node Node.
52363 * @param {Array.<*>} objectStack Object stack.
52364 * @private
52365 */
52366ol.format.OSMXML.readTag_ = function(node, objectStack) {
52367 var values = /** @type {Object} */ (objectStack[objectStack.length - 1]);
52368 values.tags[node.getAttribute('k')] = node.getAttribute('v');
52369};
52370
52371
52372/**
52373 * @const
52374 * @private
52375 * @type {Array.<string>}
52376 */
52377ol.format.OSMXML.NAMESPACE_URIS_ = [
52378 null
52379];
52380
52381
52382/**
52383 * @const
52384 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52385 * @private
52386 */
52387ol.format.OSMXML.WAY_PARSERS_ = ol.xml.makeStructureNS(
52388 ol.format.OSMXML.NAMESPACE_URIS_, {
52389 'nd': ol.format.OSMXML.readNd_,
52390 'tag': ol.format.OSMXML.readTag_
52391 });
52392
52393
52394/**
52395 * @const
52396 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52397 * @private
52398 */
52399ol.format.OSMXML.PARSERS_ = ol.xml.makeStructureNS(
52400 ol.format.OSMXML.NAMESPACE_URIS_, {
52401 'node': ol.format.OSMXML.readNode_,
52402 'way': ol.format.OSMXML.readWay_
52403 });
52404
52405
52406/**
52407 * @const
52408 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52409 * @private
52410 */
52411ol.format.OSMXML.NODE_PARSERS_ = ol.xml.makeStructureNS(
52412 ol.format.OSMXML.NAMESPACE_URIS_, {
52413 'tag': ol.format.OSMXML.readTag_
52414 });
52415
52416
52417/**
52418 * Read all features from an OSM source.
52419 *
52420 * @function
52421 * @param {Document|Node|Object|string} source Source.
52422 * @param {olx.format.ReadOptions=} opt_options Read options.
52423 * @return {Array.<ol.Feature>} Features.
52424 * @api
52425 */
52426ol.format.OSMXML.prototype.readFeatures;
52427
52428
52429/**
52430 * @inheritDoc
52431 */
52432ol.format.OSMXML.prototype.readFeaturesFromNode = function(node, opt_options) {
52433 var options = this.getReadOptions(node, opt_options);
52434 if (node.localName == 'osm') {
52435 var state = ol.xml.pushParseAndPop({
52436 nodes: {},
52437 features: []
52438 }, ol.format.OSMXML.PARSERS_, node, [options]);
52439 if (state.features) {
52440 return state.features;
52441 }
52442 }
52443 return [];
52444};
52445
52446
52447/**
52448 * Read the projection from an OSM source.
52449 *
52450 * @function
52451 * @param {Document|Node|Object|string} source Source.
52452 * @return {ol.proj.Projection} Projection.
52453 * @api
52454 */
52455ol.format.OSMXML.prototype.readProjection;
52456
52457
52458/**
52459 * Not implemented.
52460 * @inheritDoc
52461 */
52462ol.format.OSMXML.prototype.writeFeatureNode = function(feature, opt_options) {};
52463
52464
52465/**
52466 * Not implemented.
52467 * @inheritDoc
52468 */
52469ol.format.OSMXML.prototype.writeFeaturesNode = function(features, opt_options) {};
52470
52471
52472/**
52473 * Not implemented.
52474 * @inheritDoc
52475 */
52476ol.format.OSMXML.prototype.writeGeometryNode = function(geometry, opt_options) {};
52477
52478goog.provide('ol.format.XLink');
52479
52480
52481/**
52482 * @const
52483 * @type {string}
52484 */
52485ol.format.XLink.NAMESPACE_URI = 'http://www.w3.org/1999/xlink';
52486
52487
52488/**
52489 * @param {Node} node Node.
52490 * @return {boolean|undefined} Boolean.
52491 */
52492ol.format.XLink.readHref = function(node) {
52493 return node.getAttributeNS(ol.format.XLink.NAMESPACE_URI, 'href');
52494};
52495
52496goog.provide('ol.format.XML');
52497
52498goog.require('ol.xml');
52499
52500
52501/**
52502 * @classdesc
52503 * Generic format for reading non-feature XML data
52504 *
52505 * @constructor
52506 * @abstract
52507 * @struct
52508 */
52509ol.format.XML = function() {
52510};
52511
52512
52513/**
52514 * @param {Document|Node|string} source Source.
52515 * @return {Object} The parsed result.
52516 */
52517ol.format.XML.prototype.read = function(source) {
52518 if (ol.xml.isDocument(source)) {
52519 return this.readFromDocument(/** @type {Document} */ (source));
52520 } else if (ol.xml.isNode(source)) {
52521 return this.readFromNode(/** @type {Node} */ (source));
52522 } else if (typeof source === 'string') {
52523 var doc = ol.xml.parse(source);
52524 return this.readFromDocument(doc);
52525 } else {
52526 return null;
52527 }
52528};
52529
52530
52531/**
52532 * @abstract
52533 * @param {Document} doc Document.
52534 * @return {Object} Object
52535 */
52536ol.format.XML.prototype.readFromDocument = function(doc) {};
52537
52538
52539/**
52540 * @abstract
52541 * @param {Node} node Node.
52542 * @return {Object} Object
52543 */
52544ol.format.XML.prototype.readFromNode = function(node) {};
52545
52546goog.provide('ol.format.OWS');
52547
52548goog.require('ol');
52549goog.require('ol.format.XLink');
52550goog.require('ol.format.XML');
52551goog.require('ol.format.XSD');
52552goog.require('ol.xml');
52553
52554
52555/**
52556 * @constructor
52557 * @extends {ol.format.XML}
52558 */
52559ol.format.OWS = function() {
52560 ol.format.XML.call(this);
52561};
52562ol.inherits(ol.format.OWS, ol.format.XML);
52563
52564
52565/**
52566 * @inheritDoc
52567 */
52568ol.format.OWS.prototype.readFromDocument = function(doc) {
52569 for (var n = doc.firstChild; n; n = n.nextSibling) {
52570 if (n.nodeType == Node.ELEMENT_NODE) {
52571 return this.readFromNode(n);
52572 }
52573 }
52574 return null;
52575};
52576
52577
52578/**
52579 * @inheritDoc
52580 */
52581ol.format.OWS.prototype.readFromNode = function(node) {
52582 var owsObject = ol.xml.pushParseAndPop({},
52583 ol.format.OWS.PARSERS_, node, []);
52584 return owsObject ? owsObject : null;
52585};
52586
52587
52588/**
52589 * @param {Node} node Node.
52590 * @param {Array.<*>} objectStack Object stack.
52591 * @private
52592 * @return {Object|undefined} The address.
52593 */
52594ol.format.OWS.readAddress_ = function(node, objectStack) {
52595 return ol.xml.pushParseAndPop({},
52596 ol.format.OWS.ADDRESS_PARSERS_, node, objectStack);
52597};
52598
52599
52600/**
52601 * @param {Node} node Node.
52602 * @param {Array.<*>} objectStack Object stack.
52603 * @private
52604 * @return {Object|undefined} The values.
52605 */
52606ol.format.OWS.readAllowedValues_ = function(node, objectStack) {
52607 return ol.xml.pushParseAndPop({},
52608 ol.format.OWS.ALLOWED_VALUES_PARSERS_, node, objectStack);
52609};
52610
52611
52612/**
52613 * @param {Node} node Node.
52614 * @param {Array.<*>} objectStack Object stack.
52615 * @private
52616 * @return {Object|undefined} The constraint.
52617 */
52618ol.format.OWS.readConstraint_ = function(node, objectStack) {
52619 var name = node.getAttribute('name');
52620 if (!name) {
52621 return undefined;
52622 }
52623 return ol.xml.pushParseAndPop({'name': name},
52624 ol.format.OWS.CONSTRAINT_PARSERS_, node,
52625 objectStack);
52626};
52627
52628
52629/**
52630 * @param {Node} node Node.
52631 * @param {Array.<*>} objectStack Object stack.
52632 * @private
52633 * @return {Object|undefined} The contact info.
52634 */
52635ol.format.OWS.readContactInfo_ = function(node, objectStack) {
52636 return ol.xml.pushParseAndPop({},
52637 ol.format.OWS.CONTACT_INFO_PARSERS_, node, objectStack);
52638};
52639
52640
52641/**
52642 * @param {Node} node Node.
52643 * @param {Array.<*>} objectStack Object stack.
52644 * @private
52645 * @return {Object|undefined} The DCP.
52646 */
52647ol.format.OWS.readDcp_ = function(node, objectStack) {
52648 return ol.xml.pushParseAndPop({},
52649 ol.format.OWS.DCP_PARSERS_, node, objectStack);
52650};
52651
52652
52653/**
52654 * @param {Node} node Node.
52655 * @param {Array.<*>} objectStack Object stack.
52656 * @private
52657 * @return {Object|undefined} The GET object.
52658 */
52659ol.format.OWS.readGet_ = function(node, objectStack) {
52660 var href = ol.format.XLink.readHref(node);
52661 if (!href) {
52662 return undefined;
52663 }
52664 return ol.xml.pushParseAndPop({'href': href},
52665 ol.format.OWS.REQUEST_METHOD_PARSERS_, node, objectStack);
52666};
52667
52668
52669/**
52670 * @param {Node} node Node.
52671 * @param {Array.<*>} objectStack Object stack.
52672 * @private
52673 * @return {Object|undefined} The HTTP object.
52674 */
52675ol.format.OWS.readHttp_ = function(node, objectStack) {
52676 return ol.xml.pushParseAndPop({}, ol.format.OWS.HTTP_PARSERS_,
52677 node, objectStack);
52678};
52679
52680
52681/**
52682 * @param {Node} node Node.
52683 * @param {Array.<*>} objectStack Object stack.
52684 * @private
52685 * @return {Object|undefined} The operation.
52686 */
52687ol.format.OWS.readOperation_ = function(node, objectStack) {
52688 var name = node.getAttribute('name');
52689 var value = ol.xml.pushParseAndPop({},
52690 ol.format.OWS.OPERATION_PARSERS_, node, objectStack);
52691 if (!value) {
52692 return undefined;
52693 }
52694 var object = /** @type {Object} */
52695 (objectStack[objectStack.length - 1]);
52696 object[name] = value;
52697};
52698
52699
52700/**
52701 * @param {Node} node Node.
52702 * @param {Array.<*>} objectStack Object stack.
52703 * @private
52704 * @return {Object|undefined} The operations metadata.
52705 */
52706ol.format.OWS.readOperationsMetadata_ = function(node,
52707 objectStack) {
52708 return ol.xml.pushParseAndPop({},
52709 ol.format.OWS.OPERATIONS_METADATA_PARSERS_, node,
52710 objectStack);
52711};
52712
52713
52714/**
52715 * @param {Node} node Node.
52716 * @param {Array.<*>} objectStack Object stack.
52717 * @private
52718 * @return {Object|undefined} The phone.
52719 */
52720ol.format.OWS.readPhone_ = function(node, objectStack) {
52721 return ol.xml.pushParseAndPop({},
52722 ol.format.OWS.PHONE_PARSERS_, node, objectStack);
52723};
52724
52725
52726/**
52727 * @param {Node} node Node.
52728 * @param {Array.<*>} objectStack Object stack.
52729 * @private
52730 * @return {Object|undefined} The service identification.
52731 */
52732ol.format.OWS.readServiceIdentification_ = function(node,
52733 objectStack) {
52734 return ol.xml.pushParseAndPop(
52735 {}, ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_, node,
52736 objectStack);
52737};
52738
52739
52740/**
52741 * @param {Node} node Node.
52742 * @param {Array.<*>} objectStack Object stack.
52743 * @private
52744 * @return {Object|undefined} The service contact.
52745 */
52746ol.format.OWS.readServiceContact_ = function(node, objectStack) {
52747 return ol.xml.pushParseAndPop(
52748 {}, ol.format.OWS.SERVICE_CONTACT_PARSERS_, node,
52749 objectStack);
52750};
52751
52752
52753/**
52754 * @param {Node} node Node.
52755 * @param {Array.<*>} objectStack Object stack.
52756 * @private
52757 * @return {Object|undefined} The service provider.
52758 */
52759ol.format.OWS.readServiceProvider_ = function(node, objectStack) {
52760 return ol.xml.pushParseAndPop(
52761 {}, ol.format.OWS.SERVICE_PROVIDER_PARSERS_, node,
52762 objectStack);
52763};
52764
52765
52766/**
52767 * @param {Node} node Node.
52768 * @param {Array.<*>} objectStack Object stack.
52769 * @private
52770 * @return {string|undefined} The value.
52771 */
52772ol.format.OWS.readValue_ = function(node, objectStack) {
52773 return ol.format.XSD.readString(node);
52774};
52775
52776
52777/**
52778 * @const
52779 * @type {Array.<string>}
52780 * @private
52781 */
52782ol.format.OWS.NAMESPACE_URIS_ = [
52783 null,
52784 'http://www.opengis.net/ows/1.1'
52785];
52786
52787
52788/**
52789 * @const
52790 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52791 * @private
52792 */
52793ol.format.OWS.PARSERS_ = ol.xml.makeStructureNS(
52794 ol.format.OWS.NAMESPACE_URIS_, {
52795 'ServiceIdentification': ol.xml.makeObjectPropertySetter(
52796 ol.format.OWS.readServiceIdentification_),
52797 'ServiceProvider': ol.xml.makeObjectPropertySetter(
52798 ol.format.OWS.readServiceProvider_),
52799 'OperationsMetadata': ol.xml.makeObjectPropertySetter(
52800 ol.format.OWS.readOperationsMetadata_)
52801 });
52802
52803
52804/**
52805 * @const
52806 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52807 * @private
52808 */
52809ol.format.OWS.ADDRESS_PARSERS_ = ol.xml.makeStructureNS(
52810 ol.format.OWS.NAMESPACE_URIS_, {
52811 'DeliveryPoint': ol.xml.makeObjectPropertySetter(
52812 ol.format.XSD.readString),
52813 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52814 'AdministrativeArea': ol.xml.makeObjectPropertySetter(
52815 ol.format.XSD.readString),
52816 'PostalCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52817 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52818 'ElectronicMailAddress': ol.xml.makeObjectPropertySetter(
52819 ol.format.XSD.readString)
52820 });
52821
52822
52823/**
52824 * @const
52825 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52826 * @private
52827 */
52828ol.format.OWS.ALLOWED_VALUES_PARSERS_ = ol.xml.makeStructureNS(
52829 ol.format.OWS.NAMESPACE_URIS_, {
52830 'Value': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readValue_)
52831 });
52832
52833
52834/**
52835 * @const
52836 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52837 * @private
52838 */
52839ol.format.OWS.CONSTRAINT_PARSERS_ = ol.xml.makeStructureNS(
52840 ol.format.OWS.NAMESPACE_URIS_, {
52841 'AllowedValues': ol.xml.makeObjectPropertySetter(
52842 ol.format.OWS.readAllowedValues_)
52843 });
52844
52845
52846/**
52847 * @const
52848 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52849 * @private
52850 */
52851ol.format.OWS.CONTACT_INFO_PARSERS_ = ol.xml.makeStructureNS(
52852 ol.format.OWS.NAMESPACE_URIS_, {
52853 'Phone': ol.xml.makeObjectPropertySetter(ol.format.OWS.readPhone_),
52854 'Address': ol.xml.makeObjectPropertySetter(ol.format.OWS.readAddress_)
52855 });
52856
52857
52858/**
52859 * @const
52860 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52861 * @private
52862 */
52863ol.format.OWS.DCP_PARSERS_ = ol.xml.makeStructureNS(
52864 ol.format.OWS.NAMESPACE_URIS_, {
52865 'HTTP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readHttp_)
52866 });
52867
52868
52869/**
52870 * @const
52871 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52872 * @private
52873 */
52874ol.format.OWS.HTTP_PARSERS_ = ol.xml.makeStructureNS(
52875 ol.format.OWS.NAMESPACE_URIS_, {
52876 'Get': ol.xml.makeObjectPropertyPusher(ol.format.OWS.readGet_),
52877 'Post': undefined // TODO
52878 });
52879
52880
52881/**
52882 * @const
52883 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52884 * @private
52885 */
52886ol.format.OWS.OPERATION_PARSERS_ = ol.xml.makeStructureNS(
52887 ol.format.OWS.NAMESPACE_URIS_, {
52888 'DCP': ol.xml.makeObjectPropertySetter(ol.format.OWS.readDcp_)
52889 });
52890
52891
52892/**
52893 * @const
52894 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52895 * @private
52896 */
52897ol.format.OWS.OPERATIONS_METADATA_PARSERS_ = ol.xml.makeStructureNS(
52898 ol.format.OWS.NAMESPACE_URIS_, {
52899 'Operation': ol.format.OWS.readOperation_
52900 });
52901
52902
52903/**
52904 * @const
52905 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52906 * @private
52907 */
52908ol.format.OWS.PHONE_PARSERS_ = ol.xml.makeStructureNS(
52909 ol.format.OWS.NAMESPACE_URIS_, {
52910 'Voice': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52911 'Facsimile': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
52912 });
52913
52914
52915/**
52916 * @const
52917 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52918 * @private
52919 */
52920ol.format.OWS.REQUEST_METHOD_PARSERS_ = ol.xml.makeStructureNS(
52921 ol.format.OWS.NAMESPACE_URIS_, {
52922 'Constraint': ol.xml.makeObjectPropertyPusher(
52923 ol.format.OWS.readConstraint_)
52924 });
52925
52926
52927/**
52928 * @const
52929 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52930 * @private
52931 */
52932ol.format.OWS.SERVICE_CONTACT_PARSERS_ =
52933 ol.xml.makeStructureNS(
52934 ol.format.OWS.NAMESPACE_URIS_, {
52935 'IndividualName': ol.xml.makeObjectPropertySetter(
52936 ol.format.XSD.readString),
52937 'PositionName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52938 'ContactInfo': ol.xml.makeObjectPropertySetter(
52939 ol.format.OWS.readContactInfo_)
52940 });
52941
52942
52943/**
52944 * @const
52945 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52946 * @private
52947 */
52948ol.format.OWS.SERVICE_IDENTIFICATION_PARSERS_ =
52949 ol.xml.makeStructureNS(
52950 ol.format.OWS.NAMESPACE_URIS_, {
52951 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52952 'ServiceTypeVersion': ol.xml.makeObjectPropertySetter(
52953 ol.format.XSD.readString),
52954 'ServiceType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
52955 });
52956
52957
52958/**
52959 * @const
52960 * @type {Object.<string, Object.<string, ol.XmlParser>>}
52961 * @private
52962 */
52963ol.format.OWS.SERVICE_PROVIDER_PARSERS_ =
52964 ol.xml.makeStructureNS(
52965 ol.format.OWS.NAMESPACE_URIS_, {
52966 'ProviderName': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
52967 'ProviderSite': ol.xml.makeObjectPropertySetter(ol.format.XLink.readHref),
52968 'ServiceContact': ol.xml.makeObjectPropertySetter(
52969 ol.format.OWS.readServiceContact_)
52970 });
52971
52972goog.provide('ol.geom.flat.flip');
52973
52974
52975/**
52976 * @param {Array.<number>} flatCoordinates Flat coordinates.
52977 * @param {number} offset Offset.
52978 * @param {number} end End.
52979 * @param {number} stride Stride.
52980 * @param {Array.<number>=} opt_dest Destination.
52981 * @param {number=} opt_destOffset Destination offset.
52982 * @return {Array.<number>} Flat coordinates.
52983 */
52984ol.geom.flat.flip.flipXY = function(flatCoordinates, offset, end, stride, opt_dest, opt_destOffset) {
52985 var dest, destOffset;
52986 if (opt_dest !== undefined) {
52987 dest = opt_dest;
52988 destOffset = opt_destOffset !== undefined ? opt_destOffset : 0;
52989 } else {
52990 dest = [];
52991 destOffset = 0;
52992 }
52993 var j = offset;
52994 while (j < end) {
52995 var x = flatCoordinates[j++];
52996 dest[destOffset++] = flatCoordinates[j++];
52997 dest[destOffset++] = x;
52998 for (var k = 2; k < stride; ++k) {
52999 dest[destOffset++] = flatCoordinates[j++];
53000 }
53001 }
53002 dest.length = destOffset;
53003 return dest;
53004};
53005
53006goog.provide('ol.format.Polyline');
53007
53008goog.require('ol');
53009goog.require('ol.asserts');
53010goog.require('ol.Feature');
53011goog.require('ol.format.Feature');
53012goog.require('ol.format.TextFeature');
53013goog.require('ol.geom.GeometryLayout');
53014goog.require('ol.geom.LineString');
53015goog.require('ol.geom.SimpleGeometry');
53016goog.require('ol.geom.flat.flip');
53017goog.require('ol.geom.flat.inflate');
53018goog.require('ol.proj');
53019
53020
53021/**
53022 * @classdesc
53023 * Feature format for reading and writing data in the Encoded
53024 * Polyline Algorithm Format.
53025 *
53026 * @constructor
53027 * @extends {ol.format.TextFeature}
53028 * @param {olx.format.PolylineOptions=} opt_options
53029 * Optional configuration object.
53030 * @api
53031 */
53032ol.format.Polyline = function(opt_options) {
53033
53034 var options = opt_options ? opt_options : {};
53035
53036 ol.format.TextFeature.call(this);
53037
53038 /**
53039 * @inheritDoc
53040 */
53041 this.defaultDataProjection = ol.proj.get('EPSG:4326');
53042
53043 /**
53044 * @private
53045 * @type {number}
53046 */
53047 this.factor_ = options.factor ? options.factor : 1e5;
53048
53049 /**
53050 * @private
53051 * @type {ol.geom.GeometryLayout}
53052 */
53053 this.geometryLayout_ = options.geometryLayout ?
53054 options.geometryLayout : ol.geom.GeometryLayout.XY;
53055};
53056ol.inherits(ol.format.Polyline, ol.format.TextFeature);
53057
53058
53059/**
53060 * Encode a list of n-dimensional points and return an encoded string
53061 *
53062 * Attention: This function will modify the passed array!
53063 *
53064 * @param {Array.<number>} numbers A list of n-dimensional points.
53065 * @param {number} stride The number of dimension of the points in the list.
53066 * @param {number=} opt_factor The factor by which the numbers will be
53067 * multiplied. The remaining decimal places will get rounded away.
53068 * Default is `1e5`.
53069 * @return {string} The encoded string.
53070 * @api
53071 */
53072ol.format.Polyline.encodeDeltas = function(numbers, stride, opt_factor) {
53073 var factor = opt_factor ? opt_factor : 1e5;
53074 var d;
53075
53076 var lastNumbers = new Array(stride);
53077 for (d = 0; d < stride; ++d) {
53078 lastNumbers[d] = 0;
53079 }
53080
53081 var i, ii;
53082 for (i = 0, ii = numbers.length; i < ii;) {
53083 for (d = 0; d < stride; ++d, ++i) {
53084 var num = numbers[i];
53085 var delta = num - lastNumbers[d];
53086 lastNumbers[d] = num;
53087
53088 numbers[i] = delta;
53089 }
53090 }
53091
53092 return ol.format.Polyline.encodeFloats(numbers, factor);
53093};
53094
53095
53096/**
53097 * Decode a list of n-dimensional points from an encoded string
53098 *
53099 * @param {string} encoded An encoded string.
53100 * @param {number} stride The number of dimension of the points in the
53101 * encoded string.
53102 * @param {number=} opt_factor The factor by which the resulting numbers will
53103 * be divided. Default is `1e5`.
53104 * @return {Array.<number>} A list of n-dimensional points.
53105 * @api
53106 */
53107ol.format.Polyline.decodeDeltas = function(encoded, stride, opt_factor) {
53108 var factor = opt_factor ? opt_factor : 1e5;
53109 var d;
53110
53111 /** @type {Array.<number>} */
53112 var lastNumbers = new Array(stride);
53113 for (d = 0; d < stride; ++d) {
53114 lastNumbers[d] = 0;
53115 }
53116
53117 var numbers = ol.format.Polyline.decodeFloats(encoded, factor);
53118
53119 var i, ii;
53120 for (i = 0, ii = numbers.length; i < ii;) {
53121 for (d = 0; d < stride; ++d, ++i) {
53122 lastNumbers[d] += numbers[i];
53123
53124 numbers[i] = lastNumbers[d];
53125 }
53126 }
53127
53128 return numbers;
53129};
53130
53131
53132/**
53133 * Encode a list of floating point numbers and return an encoded string
53134 *
53135 * Attention: This function will modify the passed array!
53136 *
53137 * @param {Array.<number>} numbers A list of floating point numbers.
53138 * @param {number=} opt_factor The factor by which the numbers will be
53139 * multiplied. The remaining decimal places will get rounded away.
53140 * Default is `1e5`.
53141 * @return {string} The encoded string.
53142 * @api
53143 */
53144ol.format.Polyline.encodeFloats = function(numbers, opt_factor) {
53145 var factor = opt_factor ? opt_factor : 1e5;
53146 var i, ii;
53147 for (i = 0, ii = numbers.length; i < ii; ++i) {
53148 numbers[i] = Math.round(numbers[i] * factor);
53149 }
53150
53151 return ol.format.Polyline.encodeSignedIntegers(numbers);
53152};
53153
53154
53155/**
53156 * Decode a list of floating point numbers from an encoded string
53157 *
53158 * @param {string} encoded An encoded string.
53159 * @param {number=} opt_factor The factor by which the result will be divided.
53160 * Default is `1e5`.
53161 * @return {Array.<number>} A list of floating point numbers.
53162 * @api
53163 */
53164ol.format.Polyline.decodeFloats = function(encoded, opt_factor) {
53165 var factor = opt_factor ? opt_factor : 1e5;
53166 var numbers = ol.format.Polyline.decodeSignedIntegers(encoded);
53167 var i, ii;
53168 for (i = 0, ii = numbers.length; i < ii; ++i) {
53169 numbers[i] /= factor;
53170 }
53171 return numbers;
53172};
53173
53174
53175/**
53176 * Encode a list of signed integers and return an encoded string
53177 *
53178 * Attention: This function will modify the passed array!
53179 *
53180 * @param {Array.<number>} numbers A list of signed integers.
53181 * @return {string} The encoded string.
53182 */
53183ol.format.Polyline.encodeSignedIntegers = function(numbers) {
53184 var i, ii;
53185 for (i = 0, ii = numbers.length; i < ii; ++i) {
53186 var num = numbers[i];
53187 numbers[i] = (num < 0) ? ~(num << 1) : (num << 1);
53188 }
53189 return ol.format.Polyline.encodeUnsignedIntegers(numbers);
53190};
53191
53192
53193/**
53194 * Decode a list of signed integers from an encoded string
53195 *
53196 * @param {string} encoded An encoded string.
53197 * @return {Array.<number>} A list of signed integers.
53198 */
53199ol.format.Polyline.decodeSignedIntegers = function(encoded) {
53200 var numbers = ol.format.Polyline.decodeUnsignedIntegers(encoded);
53201 var i, ii;
53202 for (i = 0, ii = numbers.length; i < ii; ++i) {
53203 var num = numbers[i];
53204 numbers[i] = (num & 1) ? ~(num >> 1) : (num >> 1);
53205 }
53206 return numbers;
53207};
53208
53209
53210/**
53211 * Encode a list of unsigned integers and return an encoded string
53212 *
53213 * @param {Array.<number>} numbers A list of unsigned integers.
53214 * @return {string} The encoded string.
53215 */
53216ol.format.Polyline.encodeUnsignedIntegers = function(numbers) {
53217 var encoded = '';
53218 var i, ii;
53219 for (i = 0, ii = numbers.length; i < ii; ++i) {
53220 encoded += ol.format.Polyline.encodeUnsignedInteger(numbers[i]);
53221 }
53222 return encoded;
53223};
53224
53225
53226/**
53227 * Decode a list of unsigned integers from an encoded string
53228 *
53229 * @param {string} encoded An encoded string.
53230 * @return {Array.<number>} A list of unsigned integers.
53231 */
53232ol.format.Polyline.decodeUnsignedIntegers = function(encoded) {
53233 var numbers = [];
53234 var current = 0;
53235 var shift = 0;
53236 var i, ii;
53237 for (i = 0, ii = encoded.length; i < ii; ++i) {
53238 var b = encoded.charCodeAt(i) - 63;
53239 current |= (b & 0x1f) << shift;
53240 if (b < 0x20) {
53241 numbers.push(current);
53242 current = 0;
53243 shift = 0;
53244 } else {
53245 shift += 5;
53246 }
53247 }
53248 return numbers;
53249};
53250
53251
53252/**
53253 * Encode one single unsigned integer and return an encoded string
53254 *
53255 * @param {number} num Unsigned integer that should be encoded.
53256 * @return {string} The encoded string.
53257 */
53258ol.format.Polyline.encodeUnsignedInteger = function(num) {
53259 var value, encoded = '';
53260 while (num >= 0x20) {
53261 value = (0x20 | (num & 0x1f)) + 63;
53262 encoded += String.fromCharCode(value);
53263 num >>= 5;
53264 }
53265 value = num + 63;
53266 encoded += String.fromCharCode(value);
53267 return encoded;
53268};
53269
53270
53271/**
53272 * Read the feature from the Polyline source. The coordinates are assumed to be
53273 * in two dimensions and in latitude, longitude order.
53274 *
53275 * @function
53276 * @param {Document|Node|Object|string} source Source.
53277 * @param {olx.format.ReadOptions=} opt_options Read options.
53278 * @return {ol.Feature} Feature.
53279 * @api
53280 */
53281ol.format.Polyline.prototype.readFeature;
53282
53283
53284/**
53285 * @inheritDoc
53286 */
53287ol.format.Polyline.prototype.readFeatureFromText = function(text, opt_options) {
53288 var geometry = this.readGeometryFromText(text, opt_options);
53289 return new ol.Feature(geometry);
53290};
53291
53292
53293/**
53294 * Read the feature from the source. As Polyline sources contain a single
53295 * feature, this will return the feature in an array.
53296 *
53297 * @function
53298 * @param {Document|Node|Object|string} source Source.
53299 * @param {olx.format.ReadOptions=} opt_options Read options.
53300 * @return {Array.<ol.Feature>} Features.
53301 * @api
53302 */
53303ol.format.Polyline.prototype.readFeatures;
53304
53305
53306/**
53307 * @inheritDoc
53308 */
53309ol.format.Polyline.prototype.readFeaturesFromText = function(text, opt_options) {
53310 var feature = this.readFeatureFromText(text, opt_options);
53311 return [feature];
53312};
53313
53314
53315/**
53316 * Read the geometry from the source.
53317 *
53318 * @function
53319 * @param {Document|Node|Object|string} source Source.
53320 * @param {olx.format.ReadOptions=} opt_options Read options.
53321 * @return {ol.geom.Geometry} Geometry.
53322 * @api
53323 */
53324ol.format.Polyline.prototype.readGeometry;
53325
53326
53327/**
53328 * @inheritDoc
53329 */
53330ol.format.Polyline.prototype.readGeometryFromText = function(text, opt_options) {
53331 var stride = ol.geom.SimpleGeometry.getStrideForLayout(this.geometryLayout_);
53332 var flatCoordinates = ol.format.Polyline.decodeDeltas(
53333 text, stride, this.factor_);
53334 ol.geom.flat.flip.flipXY(
53335 flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
53336 var coordinates = ol.geom.flat.inflate.coordinates(
53337 flatCoordinates, 0, flatCoordinates.length, stride);
53338
53339 return /** @type {ol.geom.Geometry} */ (
53340 ol.format.Feature.transformWithOptions(
53341 new ol.geom.LineString(coordinates, this.geometryLayout_), false,
53342 this.adaptOptions(opt_options)));
53343};
53344
53345
53346/**
53347 * Read the projection from a Polyline source.
53348 *
53349 * @function
53350 * @param {Document|Node|Object|string} source Source.
53351 * @return {ol.proj.Projection} Projection.
53352 * @api
53353 */
53354ol.format.Polyline.prototype.readProjection;
53355
53356
53357/**
53358 * @inheritDoc
53359 */
53360ol.format.Polyline.prototype.writeFeatureText = function(feature, opt_options) {
53361 var geometry = feature.getGeometry();
53362 if (geometry) {
53363 return this.writeGeometryText(geometry, opt_options);
53364 } else {
53365 ol.asserts.assert(false, 40); // Expected `feature` to have a geometry
53366 return '';
53367 }
53368};
53369
53370
53371/**
53372 * @inheritDoc
53373 */
53374ol.format.Polyline.prototype.writeFeaturesText = function(features, opt_options) {
53375 return this.writeFeatureText(features[0], opt_options);
53376};
53377
53378
53379/**
53380 * Write a single geometry in Polyline format.
53381 *
53382 * @function
53383 * @param {ol.geom.Geometry} geometry Geometry.
53384 * @param {olx.format.WriteOptions=} opt_options Write options.
53385 * @return {string} Geometry.
53386 * @api
53387 */
53388ol.format.Polyline.prototype.writeGeometry;
53389
53390
53391/**
53392 * @inheritDoc
53393 */
53394ol.format.Polyline.prototype.writeGeometryText = function(geometry, opt_options) {
53395 geometry = /** @type {ol.geom.LineString} */
53396 (ol.format.Feature.transformWithOptions(
53397 geometry, true, this.adaptOptions(opt_options)));
53398 var flatCoordinates = geometry.getFlatCoordinates();
53399 var stride = geometry.getStride();
53400 ol.geom.flat.flip.flipXY(
53401 flatCoordinates, 0, flatCoordinates.length, stride, flatCoordinates);
53402 return ol.format.Polyline.encodeDeltas(flatCoordinates, stride, this.factor_);
53403};
53404
53405goog.provide('ol.format.TopoJSON');
53406
53407goog.require('ol');
53408goog.require('ol.Feature');
53409goog.require('ol.format.Feature');
53410goog.require('ol.format.JSONFeature');
53411goog.require('ol.geom.LineString');
53412goog.require('ol.geom.MultiLineString');
53413goog.require('ol.geom.MultiPoint');
53414goog.require('ol.geom.MultiPolygon');
53415goog.require('ol.geom.Point');
53416goog.require('ol.geom.Polygon');
53417goog.require('ol.proj');
53418
53419
53420/**
53421 * @classdesc
53422 * Feature format for reading data in the TopoJSON format.
53423 *
53424 * @constructor
53425 * @extends {ol.format.JSONFeature}
53426 * @param {olx.format.TopoJSONOptions=} opt_options Options.
53427 * @api
53428 */
53429ol.format.TopoJSON = function(opt_options) {
53430
53431 var options = opt_options ? opt_options : {};
53432
53433 ol.format.JSONFeature.call(this);
53434
53435 /**
53436 * @private
53437 * @type {string|undefined}
53438 */
53439 this.layerName_ = options.layerName;
53440
53441 /**
53442 * @private
53443 * @type {Array.<string>}
53444 */
53445 this.layers_ = options.layers ? options.layers : null;
53446
53447 /**
53448 * @inheritDoc
53449 */
53450 this.defaultDataProjection = ol.proj.get(
53451 options.defaultDataProjection ?
53452 options.defaultDataProjection : 'EPSG:4326');
53453
53454};
53455ol.inherits(ol.format.TopoJSON, ol.format.JSONFeature);
53456
53457
53458/**
53459 * Concatenate arcs into a coordinate array.
53460 * @param {Array.<number>} indices Indices of arcs to concatenate. Negative
53461 * values indicate arcs need to be reversed.
53462 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs (already
53463 * transformed).
53464 * @return {Array.<ol.Coordinate>} Coordinates array.
53465 * @private
53466 */
53467ol.format.TopoJSON.concatenateArcs_ = function(indices, arcs) {
53468 /** @type {Array.<ol.Coordinate>} */
53469 var coordinates = [];
53470 var index, arc;
53471 var i, ii;
53472 var j, jj;
53473 for (i = 0, ii = indices.length; i < ii; ++i) {
53474 index = indices[i];
53475 if (i > 0) {
53476 // splicing together arcs, discard last point
53477 coordinates.pop();
53478 }
53479 if (index >= 0) {
53480 // forward arc
53481 arc = arcs[index];
53482 } else {
53483 // reverse arc
53484 arc = arcs[~index].slice().reverse();
53485 }
53486 coordinates.push.apply(coordinates, arc);
53487 }
53488 // provide fresh copies of coordinate arrays
53489 for (j = 0, jj = coordinates.length; j < jj; ++j) {
53490 coordinates[j] = coordinates[j].slice();
53491 }
53492 return coordinates;
53493};
53494
53495
53496/**
53497 * Create a point from a TopoJSON geometry object.
53498 *
53499 * @param {TopoJSONGeometry} object TopoJSON object.
53500 * @param {Array.<number>} scale Scale for each dimension.
53501 * @param {Array.<number>} translate Translation for each dimension.
53502 * @return {ol.geom.Point} Geometry.
53503 * @private
53504 */
53505ol.format.TopoJSON.readPointGeometry_ = function(object, scale, translate) {
53506 var coordinates = object.coordinates;
53507 if (scale && translate) {
53508 ol.format.TopoJSON.transformVertex_(coordinates, scale, translate);
53509 }
53510 return new ol.geom.Point(coordinates);
53511};
53512
53513
53514/**
53515 * Create a multi-point from a TopoJSON geometry object.
53516 *
53517 * @param {TopoJSONGeometry} object TopoJSON object.
53518 * @param {Array.<number>} scale Scale for each dimension.
53519 * @param {Array.<number>} translate Translation for each dimension.
53520 * @return {ol.geom.MultiPoint} Geometry.
53521 * @private
53522 */
53523ol.format.TopoJSON.readMultiPointGeometry_ = function(object, scale,
53524 translate) {
53525 var coordinates = object.coordinates;
53526 var i, ii;
53527 if (scale && translate) {
53528 for (i = 0, ii = coordinates.length; i < ii; ++i) {
53529 ol.format.TopoJSON.transformVertex_(coordinates[i], scale, translate);
53530 }
53531 }
53532 return new ol.geom.MultiPoint(coordinates);
53533};
53534
53535
53536/**
53537 * Create a linestring from a TopoJSON geometry object.
53538 *
53539 * @param {TopoJSONGeometry} object TopoJSON object.
53540 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53541 * @return {ol.geom.LineString} Geometry.
53542 * @private
53543 */
53544ol.format.TopoJSON.readLineStringGeometry_ = function(object, arcs) {
53545 var coordinates = ol.format.TopoJSON.concatenateArcs_(object.arcs, arcs);
53546 return new ol.geom.LineString(coordinates);
53547};
53548
53549
53550/**
53551 * Create a multi-linestring from a TopoJSON geometry object.
53552 *
53553 * @param {TopoJSONGeometry} object TopoJSON object.
53554 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53555 * @return {ol.geom.MultiLineString} Geometry.
53556 * @private
53557 */
53558ol.format.TopoJSON.readMultiLineStringGeometry_ = function(object, arcs) {
53559 var coordinates = [];
53560 var i, ii;
53561 for (i = 0, ii = object.arcs.length; i < ii; ++i) {
53562 coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
53563 }
53564 return new ol.geom.MultiLineString(coordinates);
53565};
53566
53567
53568/**
53569 * Create a polygon from a TopoJSON geometry object.
53570 *
53571 * @param {TopoJSONGeometry} object TopoJSON object.
53572 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53573 * @return {ol.geom.Polygon} Geometry.
53574 * @private
53575 */
53576ol.format.TopoJSON.readPolygonGeometry_ = function(object, arcs) {
53577 var coordinates = [];
53578 var i, ii;
53579 for (i = 0, ii = object.arcs.length; i < ii; ++i) {
53580 coordinates[i] = ol.format.TopoJSON.concatenateArcs_(object.arcs[i], arcs);
53581 }
53582 return new ol.geom.Polygon(coordinates);
53583};
53584
53585
53586/**
53587 * Create a multi-polygon from a TopoJSON geometry object.
53588 *
53589 * @param {TopoJSONGeometry} object TopoJSON object.
53590 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53591 * @return {ol.geom.MultiPolygon} Geometry.
53592 * @private
53593 */
53594ol.format.TopoJSON.readMultiPolygonGeometry_ = function(object, arcs) {
53595 var coordinates = [];
53596 var polyArray, ringCoords, j, jj;
53597 var i, ii;
53598 for (i = 0, ii = object.arcs.length; i < ii; ++i) {
53599 // for each polygon
53600 polyArray = object.arcs[i];
53601 ringCoords = [];
53602 for (j = 0, jj = polyArray.length; j < jj; ++j) {
53603 // for each ring
53604 ringCoords[j] = ol.format.TopoJSON.concatenateArcs_(polyArray[j], arcs);
53605 }
53606 coordinates[i] = ringCoords;
53607 }
53608 return new ol.geom.MultiPolygon(coordinates);
53609};
53610
53611
53612/**
53613 * Create features from a TopoJSON GeometryCollection object.
53614 *
53615 * @param {TopoJSONGeometryCollection} collection TopoJSON Geometry
53616 * object.
53617 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53618 * @param {Array.<number>} scale Scale for each dimension.
53619 * @param {Array.<number>} translate Translation for each dimension.
53620 * @param {string|undefined} property Property to set the `GeometryCollection`'s parent
53621 * object to.
53622 * @param {string} name Name of the `Topology`'s child object.
53623 * @param {olx.format.ReadOptions=} opt_options Read options.
53624 * @return {Array.<ol.Feature>} Array of features.
53625 * @private
53626 */
53627ol.format.TopoJSON.readFeaturesFromGeometryCollection_ = function(
53628 collection, arcs, scale, translate, property, name, opt_options) {
53629 var geometries = collection.geometries;
53630 var features = [];
53631 var i, ii;
53632 for (i = 0, ii = geometries.length; i < ii; ++i) {
53633 features[i] = ol.format.TopoJSON.readFeatureFromGeometry_(
53634 geometries[i], arcs, scale, translate, property, name, opt_options);
53635 }
53636 return features;
53637};
53638
53639
53640/**
53641 * Create a feature from a TopoJSON geometry object.
53642 *
53643 * @param {TopoJSONGeometry} object TopoJSON geometry object.
53644 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53645 * @param {Array.<number>} scale Scale for each dimension.
53646 * @param {Array.<number>} translate Translation for each dimension.
53647 * @param {string|undefined} property Property to set the `GeometryCollection`'s parent
53648 * object to.
53649 * @param {string} name Name of the `Topology`'s child object.
53650 * @param {olx.format.ReadOptions=} opt_options Read options.
53651 * @return {ol.Feature} Feature.
53652 * @private
53653 */
53654ol.format.TopoJSON.readFeatureFromGeometry_ = function(object, arcs,
53655 scale, translate, property, name, opt_options) {
53656 var geometry;
53657 var type = object.type;
53658 var geometryReader = ol.format.TopoJSON.GEOMETRY_READERS_[type];
53659 if ((type === 'Point') || (type === 'MultiPoint')) {
53660 geometry = geometryReader(object, scale, translate);
53661 } else {
53662 geometry = geometryReader(object, arcs);
53663 }
53664 var feature = new ol.Feature();
53665 feature.setGeometry(/** @type {ol.geom.Geometry} */ (
53666 ol.format.Feature.transformWithOptions(geometry, false, opt_options)));
53667 if (object.id !== undefined) {
53668 feature.setId(object.id);
53669 }
53670 var properties = object.properties;
53671 if (property) {
53672 if (!properties) {
53673 properties = {};
53674 }
53675 properties[property] = name;
53676 }
53677 if (properties) {
53678 feature.setProperties(properties);
53679 }
53680 return feature;
53681};
53682
53683
53684/**
53685 * Read all features from a TopoJSON source.
53686 *
53687 * @function
53688 * @param {Document|Node|Object|string} source Source.
53689 * @return {Array.<ol.Feature>} Features.
53690 * @api
53691 */
53692ol.format.TopoJSON.prototype.readFeatures;
53693
53694
53695/**
53696 * @inheritDoc
53697 */
53698ol.format.TopoJSON.prototype.readFeaturesFromObject = function(
53699 object, opt_options) {
53700 if (object.type == 'Topology') {
53701 var topoJSONTopology = /** @type {TopoJSONTopology} */ (object);
53702 var transform, scale = null, translate = null;
53703 if (topoJSONTopology.transform) {
53704 transform = topoJSONTopology.transform;
53705 scale = transform.scale;
53706 translate = transform.translate;
53707 }
53708 var arcs = topoJSONTopology.arcs;
53709 if (transform) {
53710 ol.format.TopoJSON.transformArcs_(arcs, scale, translate);
53711 }
53712 /** @type {Array.<ol.Feature>} */
53713 var features = [];
53714 var topoJSONFeatures = topoJSONTopology.objects;
53715 var property = this.layerName_;
53716 var objectName, feature;
53717 for (objectName in topoJSONFeatures) {
53718 if (this.layers_ && this.layers_.indexOf(objectName) == -1) {
53719 continue;
53720 }
53721 if (topoJSONFeatures[objectName].type === 'GeometryCollection') {
53722 feature = /** @type {TopoJSONGeometryCollection} */
53723 (topoJSONFeatures[objectName]);
53724 features.push.apply(features,
53725 ol.format.TopoJSON.readFeaturesFromGeometryCollection_(
53726 feature, arcs, scale, translate, property, objectName, opt_options));
53727 } else {
53728 feature = /** @type {TopoJSONGeometry} */
53729 (topoJSONFeatures[objectName]);
53730 features.push(ol.format.TopoJSON.readFeatureFromGeometry_(
53731 feature, arcs, scale, translate, property, objectName, opt_options));
53732 }
53733 }
53734 return features;
53735 } else {
53736 return [];
53737 }
53738};
53739
53740
53741/**
53742 * Apply a linear transform to array of arcs. The provided array of arcs is
53743 * modified in place.
53744 *
53745 * @param {Array.<Array.<ol.Coordinate>>} arcs Array of arcs.
53746 * @param {Array.<number>} scale Scale for each dimension.
53747 * @param {Array.<number>} translate Translation for each dimension.
53748 * @private
53749 */
53750ol.format.TopoJSON.transformArcs_ = function(arcs, scale, translate) {
53751 var i, ii;
53752 for (i = 0, ii = arcs.length; i < ii; ++i) {
53753 ol.format.TopoJSON.transformArc_(arcs[i], scale, translate);
53754 }
53755};
53756
53757
53758/**
53759 * Apply a linear transform to an arc. The provided arc is modified in place.
53760 *
53761 * @param {Array.<ol.Coordinate>} arc Arc.
53762 * @param {Array.<number>} scale Scale for each dimension.
53763 * @param {Array.<number>} translate Translation for each dimension.
53764 * @private
53765 */
53766ol.format.TopoJSON.transformArc_ = function(arc, scale, translate) {
53767 var x = 0;
53768 var y = 0;
53769 var vertex;
53770 var i, ii;
53771 for (i = 0, ii = arc.length; i < ii; ++i) {
53772 vertex = arc[i];
53773 x += vertex[0];
53774 y += vertex[1];
53775 vertex[0] = x;
53776 vertex[1] = y;
53777 ol.format.TopoJSON.transformVertex_(vertex, scale, translate);
53778 }
53779};
53780
53781
53782/**
53783 * Apply a linear transform to a vertex. The provided vertex is modified in
53784 * place.
53785 *
53786 * @param {ol.Coordinate} vertex Vertex.
53787 * @param {Array.<number>} scale Scale for each dimension.
53788 * @param {Array.<number>} translate Translation for each dimension.
53789 * @private
53790 */
53791ol.format.TopoJSON.transformVertex_ = function(vertex, scale, translate) {
53792 vertex[0] = vertex[0] * scale[0] + translate[0];
53793 vertex[1] = vertex[1] * scale[1] + translate[1];
53794};
53795
53796
53797/**
53798 * Read the projection from a TopoJSON source.
53799 *
53800 * @param {Document|Node|Object|string} object Source.
53801 * @return {ol.proj.Projection} Projection.
53802 * @override
53803 * @api
53804 */
53805ol.format.TopoJSON.prototype.readProjection;
53806
53807
53808/**
53809 * @inheritDoc
53810 */
53811ol.format.TopoJSON.prototype.readProjectionFromObject = function(object) {
53812 return this.defaultDataProjection;
53813};
53814
53815
53816/**
53817 * @const
53818 * @private
53819 * @type {Object.<string, function(TopoJSONGeometry, Array, ...Array): ol.geom.Geometry>}
53820 */
53821ol.format.TopoJSON.GEOMETRY_READERS_ = {
53822 'Point': ol.format.TopoJSON.readPointGeometry_,
53823 'LineString': ol.format.TopoJSON.readLineStringGeometry_,
53824 'Polygon': ol.format.TopoJSON.readPolygonGeometry_,
53825 'MultiPoint': ol.format.TopoJSON.readMultiPointGeometry_,
53826 'MultiLineString': ol.format.TopoJSON.readMultiLineStringGeometry_,
53827 'MultiPolygon': ol.format.TopoJSON.readMultiPolygonGeometry_
53828};
53829
53830
53831/**
53832 * Not implemented.
53833 * @inheritDoc
53834 */
53835ol.format.TopoJSON.prototype.writeFeatureObject = function(feature, opt_options) {};
53836
53837
53838/**
53839 * Not implemented.
53840 * @inheritDoc
53841 */
53842ol.format.TopoJSON.prototype.writeFeaturesObject = function(features, opt_options) {};
53843
53844
53845/**
53846 * Not implemented.
53847 * @inheritDoc
53848 */
53849ol.format.TopoJSON.prototype.writeGeometryObject = function(geometry, opt_options) {};
53850
53851
53852/**
53853 * Not implemented.
53854 * @override
53855 */
53856ol.format.TopoJSON.prototype.readGeometryFromObject = function() {};
53857
53858
53859/**
53860 * Not implemented.
53861 * @override
53862 */
53863ol.format.TopoJSON.prototype.readFeatureFromObject = function() {};
53864
53865goog.provide('ol.format.WFS');
53866
53867goog.require('ol');
53868goog.require('ol.asserts');
53869goog.require('ol.format.GML2');
53870goog.require('ol.format.GML3');
53871goog.require('ol.format.GMLBase');
53872goog.require('ol.format.filter');
53873goog.require('ol.format.XMLFeature');
53874goog.require('ol.format.XSD');
53875goog.require('ol.geom.Geometry');
53876goog.require('ol.obj');
53877goog.require('ol.proj');
53878goog.require('ol.xml');
53879
53880
53881/**
53882 * @classdesc
53883 * Feature format for reading and writing data in the WFS format.
53884 * By default, supports WFS version 1.1.0. You can pass a GML format
53885 * as option if you want to read a WFS that contains GML2 (WFS 1.0.0).
53886 * Also see {@link ol.format.GMLBase} which is used by this format.
53887 *
53888 * @constructor
53889 * @param {olx.format.WFSOptions=} opt_options
53890 * Optional configuration object.
53891 * @extends {ol.format.XMLFeature}
53892 * @api
53893 */
53894ol.format.WFS = function(opt_options) {
53895 var options = opt_options ? opt_options : {};
53896
53897 /**
53898 * @private
53899 * @type {Array.<string>|string|undefined}
53900 */
53901 this.featureType_ = options.featureType;
53902
53903 /**
53904 * @private
53905 * @type {Object.<string, string>|string|undefined}
53906 */
53907 this.featureNS_ = options.featureNS;
53908
53909 /**
53910 * @private
53911 * @type {ol.format.GMLBase}
53912 */
53913 this.gmlFormat_ = options.gmlFormat ?
53914 options.gmlFormat : new ol.format.GML3();
53915
53916 /**
53917 * @private
53918 * @type {string}
53919 */
53920 this.schemaLocation_ = options.schemaLocation ?
53921 options.schemaLocation :
53922 ol.format.WFS.SCHEMA_LOCATIONS[ol.format.WFS.DEFAULT_VERSION];
53923
53924 ol.format.XMLFeature.call(this);
53925};
53926ol.inherits(ol.format.WFS, ol.format.XMLFeature);
53927
53928
53929/**
53930 * @const
53931 * @type {string}
53932 */
53933ol.format.WFS.FEATURE_PREFIX = 'feature';
53934
53935
53936/**
53937 * @const
53938 * @type {string}
53939 */
53940ol.format.WFS.XMLNS = 'http://www.w3.org/2000/xmlns/';
53941
53942
53943/**
53944 * @const
53945 * @type {string}
53946 */
53947ol.format.WFS.OGCNS = 'http://www.opengis.net/ogc';
53948
53949
53950/**
53951 * @const
53952 * @type {string}
53953 */
53954ol.format.WFS.WFSNS = 'http://www.opengis.net/wfs';
53955
53956
53957/**
53958 * @const
53959 * @type {string}
53960 */
53961ol.format.WFS.FESNS = 'http://www.opengis.net/fes';
53962
53963
53964/**
53965 * @const
53966 * @type {Object.<string, string>}
53967 */
53968ol.format.WFS.SCHEMA_LOCATIONS = {
53969 '1.1.0': 'http://www.opengis.net/wfs ' +
53970 'http://schemas.opengis.net/wfs/1.1.0/wfs.xsd',
53971 '1.0.0': 'http://www.opengis.net/wfs ' +
53972 'http://schemas.opengis.net/wfs/1.0.0/wfs.xsd'
53973};
53974
53975
53976/**
53977 * @const
53978 * @type {string}
53979 */
53980ol.format.WFS.DEFAULT_VERSION = '1.1.0';
53981
53982
53983/**
53984 * Read all features from a WFS FeatureCollection.
53985 *
53986 * @function
53987 * @param {Document|Node|Object|string} source Source.
53988 * @param {olx.format.ReadOptions=} opt_options Read options.
53989 * @return {Array.<ol.Feature>} Features.
53990 * @api
53991 */
53992ol.format.WFS.prototype.readFeatures;
53993
53994
53995/**
53996 * @inheritDoc
53997 */
53998ol.format.WFS.prototype.readFeaturesFromNode = function(node, opt_options) {
53999 var context = /** @type {ol.XmlNodeStackItem} */ ({
54000 'featureType': this.featureType_,
54001 'featureNS': this.featureNS_
54002 });
54003 ol.obj.assign(context, this.getReadOptions(node,
54004 opt_options ? opt_options : {}));
54005 var objectStack = [context];
54006 this.gmlFormat_.FEATURE_COLLECTION_PARSERS[ol.format.GMLBase.GMLNS][
54007 'featureMember'] =
54008 ol.xml.makeArrayPusher(ol.format.GMLBase.prototype.readFeaturesInternal);
54009 var features = ol.xml.pushParseAndPop([],
54010 this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
54011 objectStack, this.gmlFormat_);
54012 if (!features) {
54013 features = [];
54014 }
54015 return features;
54016};
54017
54018
54019/**
54020 * Read transaction response of the source.
54021 *
54022 * @param {Document|Node|Object|string} source Source.
54023 * @return {ol.WFSTransactionResponse|undefined} Transaction response.
54024 * @api
54025 */
54026ol.format.WFS.prototype.readTransactionResponse = function(source) {
54027 if (ol.xml.isDocument(source)) {
54028 return this.readTransactionResponseFromDocument(
54029 /** @type {Document} */ (source));
54030 } else if (ol.xml.isNode(source)) {
54031 return this.readTransactionResponseFromNode(/** @type {Node} */ (source));
54032 } else if (typeof source === 'string') {
54033 var doc = ol.xml.parse(source);
54034 return this.readTransactionResponseFromDocument(doc);
54035 } else {
54036 return undefined;
54037 }
54038};
54039
54040
54041/**
54042 * Read feature collection metadata of the source.
54043 *
54044 * @param {Document|Node|Object|string} source Source.
54045 * @return {ol.WFSFeatureCollectionMetadata|undefined}
54046 * FeatureCollection metadata.
54047 * @api
54048 */
54049ol.format.WFS.prototype.readFeatureCollectionMetadata = function(source) {
54050 if (ol.xml.isDocument(source)) {
54051 return this.readFeatureCollectionMetadataFromDocument(
54052 /** @type {Document} */ (source));
54053 } else if (ol.xml.isNode(source)) {
54054 return this.readFeatureCollectionMetadataFromNode(
54055 /** @type {Node} */ (source));
54056 } else if (typeof source === 'string') {
54057 var doc = ol.xml.parse(source);
54058 return this.readFeatureCollectionMetadataFromDocument(doc);
54059 } else {
54060 return undefined;
54061 }
54062};
54063
54064
54065/**
54066 * @param {Document} doc Document.
54067 * @return {ol.WFSFeatureCollectionMetadata|undefined}
54068 * FeatureCollection metadata.
54069 */
54070ol.format.WFS.prototype.readFeatureCollectionMetadataFromDocument = function(doc) {
54071 for (var n = doc.firstChild; n; n = n.nextSibling) {
54072 if (n.nodeType == Node.ELEMENT_NODE) {
54073 return this.readFeatureCollectionMetadataFromNode(n);
54074 }
54075 }
54076 return undefined;
54077};
54078
54079
54080/**
54081 * @const
54082 * @type {Object.<string, Object.<string, ol.XmlParser>>}
54083 * @private
54084 */
54085ol.format.WFS.FEATURE_COLLECTION_PARSERS_ = {
54086 'http://www.opengis.net/gml': {
54087 'boundedBy': ol.xml.makeObjectPropertySetter(
54088 ol.format.GMLBase.prototype.readGeometryElement, 'bounds')
54089 }
54090};
54091
54092
54093/**
54094 * @param {Node} node Node.
54095 * @return {ol.WFSFeatureCollectionMetadata|undefined}
54096 * FeatureCollection metadata.
54097 */
54098ol.format.WFS.prototype.readFeatureCollectionMetadataFromNode = function(node) {
54099 var result = {};
54100 var value = ol.format.XSD.readNonNegativeIntegerString(
54101 node.getAttribute('numberOfFeatures'));
54102 result['numberOfFeatures'] = value;
54103 return ol.xml.pushParseAndPop(
54104 /** @type {ol.WFSFeatureCollectionMetadata} */ (result),
54105 ol.format.WFS.FEATURE_COLLECTION_PARSERS_, node, [], this.gmlFormat_);
54106};
54107
54108
54109/**
54110 * @const
54111 * @type {Object.<string, Object.<string, ol.XmlParser>>}
54112 * @private
54113 */
54114ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_ = {
54115 'http://www.opengis.net/wfs': {
54116 'totalInserted': ol.xml.makeObjectPropertySetter(
54117 ol.format.XSD.readNonNegativeInteger),
54118 'totalUpdated': ol.xml.makeObjectPropertySetter(
54119 ol.format.XSD.readNonNegativeInteger),
54120 'totalDeleted': ol.xml.makeObjectPropertySetter(
54121 ol.format.XSD.readNonNegativeInteger)
54122 }
54123};
54124
54125
54126/**
54127 * @param {Node} node Node.
54128 * @param {Array.<*>} objectStack Object stack.
54129 * @return {Object|undefined} Transaction Summary.
54130 * @private
54131 */
54132ol.format.WFS.readTransactionSummary_ = function(node, objectStack) {
54133 return ol.xml.pushParseAndPop(
54134 {}, ol.format.WFS.TRANSACTION_SUMMARY_PARSERS_, node, objectStack);
54135};
54136
54137
54138/**
54139 * @const
54140 * @type {Object.<string, Object.<string, ol.XmlParser>>}
54141 * @private
54142 */
54143ol.format.WFS.OGC_FID_PARSERS_ = {
54144 'http://www.opengis.net/ogc': {
54145 'FeatureId': ol.xml.makeArrayPusher(function(node, objectStack) {
54146 return node.getAttribute('fid');
54147 })
54148 }
54149};
54150
54151
54152/**
54153 * @param {Node} node Node.
54154 * @param {Array.<*>} objectStack Object stack.
54155 * @private
54156 */
54157ol.format.WFS.fidParser_ = function(node, objectStack) {
54158 ol.xml.parseNode(ol.format.WFS.OGC_FID_PARSERS_, node, objectStack);
54159};
54160
54161
54162/**
54163 * @const
54164 * @type {Object.<string, Object.<string, ol.XmlParser>>}
54165 * @private
54166 */
54167ol.format.WFS.INSERT_RESULTS_PARSERS_ = {
54168 'http://www.opengis.net/wfs': {
54169 'Feature': ol.format.WFS.fidParser_
54170 }
54171};
54172
54173
54174/**
54175 * @param {Node} node Node.
54176 * @param {Array.<*>} objectStack Object stack.
54177 * @return {Array.<string>|undefined} Insert results.
54178 * @private
54179 */
54180ol.format.WFS.readInsertResults_ = function(node, objectStack) {
54181 return ol.xml.pushParseAndPop(
54182 [], ol.format.WFS.INSERT_RESULTS_PARSERS_, node, objectStack);
54183};
54184
54185
54186/**
54187 * @const
54188 * @type {Object.<string, Object.<string, ol.XmlParser>>}
54189 * @private
54190 */
54191ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_ = {
54192 'http://www.opengis.net/wfs': {
54193 'TransactionSummary': ol.xml.makeObjectPropertySetter(
54194 ol.format.WFS.readTransactionSummary_, 'transactionSummary'),
54195 'InsertResults': ol.xml.makeObjectPropertySetter(
54196 ol.format.WFS.readInsertResults_, 'insertIds')
54197 }
54198};
54199
54200
54201/**
54202 * @param {Document} doc Document.
54203 * @return {ol.WFSTransactionResponse|undefined} Transaction response.
54204 */
54205ol.format.WFS.prototype.readTransactionResponseFromDocument = function(doc) {
54206 for (var n = doc.firstChild; n; n = n.nextSibling) {
54207 if (n.nodeType == Node.ELEMENT_NODE) {
54208 return this.readTransactionResponseFromNode(n);
54209 }
54210 }
54211 return undefined;
54212};
54213
54214
54215/**
54216 * @param {Node} node Node.
54217 * @return {ol.WFSTransactionResponse|undefined} Transaction response.
54218 */
54219ol.format.WFS.prototype.readTransactionResponseFromNode = function(node) {
54220 return ol.xml.pushParseAndPop(
54221 /** @type {ol.WFSTransactionResponse} */({}),
54222 ol.format.WFS.TRANSACTION_RESPONSE_PARSERS_, node, []);
54223};
54224
54225
54226/**
54227 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
54228 * @private
54229 */
54230ol.format.WFS.QUERY_SERIALIZERS_ = {
54231 'http://www.opengis.net/wfs': {
54232 'PropertyName': ol.xml.makeChildAppender(ol.format.XSD.writeStringTextNode)
54233 }
54234};
54235
54236
54237/**
54238 * @param {Node} node Node.
54239 * @param {ol.Feature} feature Feature.
54240 * @param {Array.<*>} objectStack Node stack.
54241 * @private
54242 */
54243ol.format.WFS.writeFeature_ = function(node, feature, objectStack) {
54244 var context = objectStack[objectStack.length - 1];
54245 var featureType = context['featureType'];
54246 var featureNS = context['featureNS'];
54247 var gmlVersion = context['gmlVersion'];
54248 var child = ol.xml.createElementNS(featureNS, featureType);
54249 node.appendChild(child);
54250 if (gmlVersion === 2) {
54251 ol.format.GML2.prototype.writeFeatureElement(child, feature, objectStack);
54252 } else {
54253 ol.format.GML3.prototype.writeFeatureElement(child, feature, objectStack);
54254 }
54255};
54256
54257
54258/**
54259 * @param {Node} node Node.
54260 * @param {number|string} fid Feature identifier.
54261 * @param {Array.<*>} objectStack Node stack.
54262 * @private
54263 */
54264ol.format.WFS.writeOgcFidFilter_ = function(node, fid, objectStack) {
54265 var filter = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'Filter');
54266 var child = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'FeatureId');
54267 filter.appendChild(child);
54268 child.setAttribute('fid', fid);
54269 node.appendChild(filter);
54270};
54271
54272
54273/**
54274 * @param {string|undefined} featurePrefix The prefix of the feature.
54275 * @param {string} featureType The type of the feature.
54276 * @returns {string} The value of the typeName property.
54277 * @private
54278 */
54279ol.format.WFS.getTypeName_ = function(featurePrefix, featureType) {
54280 featurePrefix = featurePrefix ? featurePrefix :
54281 ol.format.WFS.FEATURE_PREFIX;
54282 var prefix = featurePrefix + ':';
54283 // The featureType already contains the prefix.
54284 if (featureType.indexOf(prefix) === 0) {
54285 return featureType;
54286 } else {
54287 return prefix + featureType;
54288 }
54289};
54290
54291
54292/**
54293 * @param {Node} node Node.
54294 * @param {ol.Feature} feature Feature.
54295 * @param {Array.<*>} objectStack Node stack.
54296 * @private
54297 */
54298ol.format.WFS.writeDelete_ = function(node, feature, objectStack) {
54299 var context = objectStack[objectStack.length - 1];
54300 ol.asserts.assert(feature.getId() !== undefined, 26); // Features must have an id set
54301 var featureType = context['featureType'];
54302 var featurePrefix = context['featurePrefix'];
54303 var featureNS = context['featureNS'];
54304 var typeName = ol.format.WFS.getTypeName_(featurePrefix, featureType);
54305 node.setAttribute('typeName', typeName);
54306 ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
54307 featureNS);
54308 var fid = feature.getId();
54309 if (fid !== undefined) {
54310 ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
54311 }
54312};
54313
54314
54315/**
54316 * @param {Node} node Node.
54317 * @param {ol.Feature} feature Feature.
54318 * @param {Array.<*>} objectStack Node stack.
54319 * @private
54320 */
54321ol.format.WFS.writeUpdate_ = function(node, feature, objectStack) {
54322 var context = objectStack[objectStack.length - 1];
54323 ol.asserts.assert(feature.getId() !== undefined, 27); // Features must have an id set
54324 var featureType = context['featureType'];
54325 var featurePrefix = context['featurePrefix'];
54326 var featureNS = context['featureNS'];
54327 var typeName = ol.format.WFS.getTypeName_(featurePrefix, featureType);
54328 node.setAttribute('typeName', typeName);
54329 ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
54330 featureNS);
54331 var fid = feature.getId();
54332 if (fid !== undefined) {
54333 var keys = feature.getKeys();
54334 var values = [];
54335 for (var i = 0, ii = keys.length; i < ii; i++) {
54336 var value = feature.get(keys[i]);
54337 if (value !== undefined) {
54338 values.push({name: keys[i], value: value});
54339 }
54340 }
54341 ol.xml.pushSerializeAndPop(/** @type {ol.XmlNodeStackItem} */ (
54342 {'gmlVersion': context['gmlVersion'], node: node,
54343 'hasZ': context['hasZ'], 'srsName': context['srsName']}),
54344 ol.format.WFS.TRANSACTION_SERIALIZERS_,
54345 ol.xml.makeSimpleNodeFactory('Property'), values,
54346 objectStack);
54347 ol.format.WFS.writeOgcFidFilter_(node, fid, objectStack);
54348 }
54349};
54350
54351
54352/**
54353 * @param {Node} node Node.
54354 * @param {Object} pair Property name and value.
54355 * @param {Array.<*>} objectStack Node stack.
54356 * @private
54357 */
54358ol.format.WFS.writeProperty_ = function(node, pair, objectStack) {
54359 var name = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Name');
54360 var context = objectStack[objectStack.length - 1];
54361 var gmlVersion = context['gmlVersion'];
54362 node.appendChild(name);
54363 ol.format.XSD.writeStringTextNode(name, pair.name);
54364 if (pair.value !== undefined && pair.value !== null) {
54365 var value = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Value');
54366 node.appendChild(value);
54367 if (pair.value instanceof ol.geom.Geometry) {
54368 if (gmlVersion === 2) {
54369 ol.format.GML2.prototype.writeGeometryElement(value,
54370 pair.value, objectStack);
54371 } else {
54372 ol.format.GML3.prototype.writeGeometryElement(value,
54373 pair.value, objectStack);
54374 }
54375 } else {
54376 ol.format.XSD.writeStringTextNode(value, pair.value);
54377 }
54378 }
54379};
54380
54381
54382/**
54383 * @param {Node} node Node.
54384 * @param {{vendorId: string, safeToIgnore: boolean, value: string}}
54385 * nativeElement The native element.
54386 * @param {Array.<*>} objectStack Node stack.
54387 * @private
54388 */
54389ol.format.WFS.writeNative_ = function(node, nativeElement, objectStack) {
54390 if (nativeElement.vendorId) {
54391 node.setAttribute('vendorId', nativeElement.vendorId);
54392 }
54393 if (nativeElement.safeToIgnore !== undefined) {
54394 node.setAttribute('safeToIgnore', nativeElement.safeToIgnore);
54395 }
54396 if (nativeElement.value !== undefined) {
54397 ol.format.XSD.writeStringTextNode(node, nativeElement.value);
54398 }
54399};
54400
54401
54402/**
54403 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
54404 * @private
54405 */
54406ol.format.WFS.TRANSACTION_SERIALIZERS_ = {
54407 'http://www.opengis.net/wfs': {
54408 'Insert': ol.xml.makeChildAppender(ol.format.WFS.writeFeature_),
54409 'Update': ol.xml.makeChildAppender(ol.format.WFS.writeUpdate_),
54410 'Delete': ol.xml.makeChildAppender(ol.format.WFS.writeDelete_),
54411 'Property': ol.xml.makeChildAppender(ol.format.WFS.writeProperty_),
54412 'Native': ol.xml.makeChildAppender(ol.format.WFS.writeNative_)
54413 }
54414};
54415
54416
54417/**
54418 * @param {Node} node Node.
54419 * @param {string} featureType Feature type.
54420 * @param {Array.<*>} objectStack Node stack.
54421 * @private
54422 */
54423ol.format.WFS.writeQuery_ = function(node, featureType, objectStack) {
54424 var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);
54425 var featurePrefix = context['featurePrefix'];
54426 var featureNS = context['featureNS'];
54427 var propertyNames = context['propertyNames'];
54428 var srsName = context['srsName'];
54429 var typeName;
54430 // If feature prefix is not defined, we must not use the default prefix.
54431 if (featurePrefix) {
54432 typeName = ol.format.WFS.getTypeName_(featurePrefix, featureType);
54433 } else {
54434 typeName = featureType;
54435 }
54436 node.setAttribute('typeName', typeName);
54437 if (srsName) {
54438 node.setAttribute('srsName', srsName);
54439 }
54440 if (featureNS) {
54441 ol.xml.setAttributeNS(node, ol.format.WFS.XMLNS, 'xmlns:' + featurePrefix,
54442 featureNS);
54443 }
54444 var item = /** @type {ol.XmlNodeStackItem} */ (ol.obj.assign({}, context));
54445 item.node = node;
54446 ol.xml.pushSerializeAndPop(item,
54447 ol.format.WFS.QUERY_SERIALIZERS_,
54448 ol.xml.makeSimpleNodeFactory('PropertyName'), propertyNames,
54449 objectStack);
54450 var filter = context['filter'];
54451 if (filter) {
54452 var child = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'Filter');
54453 node.appendChild(child);
54454 ol.format.WFS.writeFilterCondition_(child, filter, objectStack);
54455 }
54456};
54457
54458
54459/**
54460 * @param {Node} node Node.
54461 * @param {ol.format.filter.Filter} filter Filter.
54462 * @param {Array.<*>} objectStack Node stack.
54463 * @private
54464 */
54465ol.format.WFS.writeFilterCondition_ = function(node, filter, objectStack) {
54466 /** @type {ol.XmlNodeStackItem} */
54467 var item = {node: node};
54468 ol.xml.pushSerializeAndPop(item,
54469 ol.format.WFS.GETFEATURE_SERIALIZERS_,
54470 ol.xml.makeSimpleNodeFactory(filter.getTagName()),
54471 [filter], objectStack);
54472};
54473
54474
54475/**
54476 * @param {Node} node Node.
54477 * @param {ol.format.filter.Bbox} filter Filter.
54478 * @param {Array.<*>} objectStack Node stack.
54479 * @private
54480 */
54481ol.format.WFS.writeBboxFilter_ = function(node, filter, objectStack) {
54482 var context = objectStack[objectStack.length - 1];
54483 context['srsName'] = filter.srsName;
54484
54485 ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);
54486 ol.format.GML3.prototype.writeGeometryElement(node, filter.extent, objectStack);
54487};
54488
54489
54490/**
54491 * @param {Node} node Node.
54492 * @param {ol.format.filter.Intersects} filter Filter.
54493 * @param {Array.<*>} objectStack Node stack.
54494 * @private
54495 */
54496ol.format.WFS.writeIntersectsFilter_ = function(node, filter, objectStack) {
54497 var context = objectStack[objectStack.length - 1];
54498 context['srsName'] = filter.srsName;
54499
54500 ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);
54501 ol.format.GML3.prototype.writeGeometryElement(node, filter.geometry, objectStack);
54502};
54503
54504
54505/**
54506 * @param {Node} node Node.
54507 * @param {ol.format.filter.Within} filter Filter.
54508 * @param {Array.<*>} objectStack Node stack.
54509 * @private
54510 */
54511ol.format.WFS.writeWithinFilter_ = function(node, filter, objectStack) {
54512 var context = objectStack[objectStack.length - 1];
54513 context['srsName'] = filter.srsName;
54514
54515 ol.format.WFS.writeOgcPropertyName_(node, filter.geometryName);
54516 ol.format.GML3.prototype.writeGeometryElement(node, filter.geometry, objectStack);
54517};
54518
54519
54520/**
54521 * @param {Node} node Node.
54522 * @param {ol.format.filter.During} filter Filter.
54523 * @param {Array.<*>} objectStack Node stack.
54524 * @private
54525 */
54526ol.format.WFS.writeDuringFilter_ = function(node, filter, objectStack) {
54527
54528 var valueReference = ol.xml.createElementNS(ol.format.WFS.FESNS, 'ValueReference');
54529 ol.format.XSD.writeStringTextNode(valueReference, filter.propertyName);
54530 node.appendChild(valueReference);
54531
54532 var timePeriod = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'TimePeriod');
54533
54534 node.appendChild(timePeriod);
54535
54536 var begin = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'begin');
54537 timePeriod.appendChild(begin);
54538 ol.format.WFS.writeTimeInstant_(begin, filter.begin);
54539
54540 var end = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'end');
54541 timePeriod.appendChild(end);
54542 ol.format.WFS.writeTimeInstant_(end, filter.end);
54543};
54544
54545
54546/**
54547 * @param {Node} node Node.
54548 * @param {ol.format.filter.LogicalNary} filter Filter.
54549 * @param {Array.<*>} objectStack Node stack.
54550 * @private
54551 */
54552ol.format.WFS.writeLogicalFilter_ = function(node, filter, objectStack) {
54553 /** @type {ol.XmlNodeStackItem} */
54554 var item = {node: node};
54555 var conditions = filter.conditions;
54556 for (var i = 0, ii = conditions.length; i < ii; ++i) {
54557 var condition = conditions[i];
54558 ol.xml.pushSerializeAndPop(item,
54559 ol.format.WFS.GETFEATURE_SERIALIZERS_,
54560 ol.xml.makeSimpleNodeFactory(condition.getTagName()),
54561 [condition], objectStack);
54562 }
54563};
54564
54565
54566/**
54567 * @param {Node} node Node.
54568 * @param {ol.format.filter.Not} filter Filter.
54569 * @param {Array.<*>} objectStack Node stack.
54570 * @private
54571 */
54572ol.format.WFS.writeNotFilter_ = function(node, filter, objectStack) {
54573 /** @type {ol.XmlNodeStackItem} */
54574 var item = {node: node};
54575 var condition = filter.condition;
54576 ol.xml.pushSerializeAndPop(item,
54577 ol.format.WFS.GETFEATURE_SERIALIZERS_,
54578 ol.xml.makeSimpleNodeFactory(condition.getTagName()),
54579 [condition], objectStack);
54580};
54581
54582
54583/**
54584 * @param {Node} node Node.
54585 * @param {ol.format.filter.ComparisonBinary} filter Filter.
54586 * @param {Array.<*>} objectStack Node stack.
54587 * @private
54588 */
54589ol.format.WFS.writeComparisonFilter_ = function(node, filter, objectStack) {
54590 if (filter.matchCase !== undefined) {
54591 node.setAttribute('matchCase', filter.matchCase.toString());
54592 }
54593 ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
54594 ol.format.WFS.writeOgcLiteral_(node, '' + filter.expression);
54595};
54596
54597
54598/**
54599 * @param {Node} node Node.
54600 * @param {ol.format.filter.IsNull} filter Filter.
54601 * @param {Array.<*>} objectStack Node stack.
54602 * @private
54603 */
54604ol.format.WFS.writeIsNullFilter_ = function(node, filter, objectStack) {
54605 ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
54606};
54607
54608
54609/**
54610 * @param {Node} node Node.
54611 * @param {ol.format.filter.IsBetween} filter Filter.
54612 * @param {Array.<*>} objectStack Node stack.
54613 * @private
54614 */
54615ol.format.WFS.writeIsBetweenFilter_ = function(node, filter, objectStack) {
54616 ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
54617
54618 var lowerBoundary = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'LowerBoundary');
54619 node.appendChild(lowerBoundary);
54620 ol.format.WFS.writeOgcLiteral_(lowerBoundary, '' + filter.lowerBoundary);
54621
54622 var upperBoundary = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'UpperBoundary');
54623 node.appendChild(upperBoundary);
54624 ol.format.WFS.writeOgcLiteral_(upperBoundary, '' + filter.upperBoundary);
54625};
54626
54627
54628/**
54629 * @param {Node} node Node.
54630 * @param {ol.format.filter.IsLike} filter Filter.
54631 * @param {Array.<*>} objectStack Node stack.
54632 * @private
54633 */
54634ol.format.WFS.writeIsLikeFilter_ = function(node, filter, objectStack) {
54635 node.setAttribute('wildCard', filter.wildCard);
54636 node.setAttribute('singleChar', filter.singleChar);
54637 node.setAttribute('escapeChar', filter.escapeChar);
54638 if (filter.matchCase !== undefined) {
54639 node.setAttribute('matchCase', filter.matchCase.toString());
54640 }
54641 ol.format.WFS.writeOgcPropertyName_(node, filter.propertyName);
54642 ol.format.WFS.writeOgcLiteral_(node, '' + filter.pattern);
54643};
54644
54645
54646/**
54647 * @param {string} tagName Tag name.
54648 * @param {Node} node Node.
54649 * @param {string} value Value.
54650 * @private
54651 */
54652ol.format.WFS.writeOgcExpression_ = function(tagName, node, value) {
54653 var property = ol.xml.createElementNS(ol.format.WFS.OGCNS, tagName);
54654 ol.format.XSD.writeStringTextNode(property, value);
54655 node.appendChild(property);
54656};
54657
54658
54659/**
54660 * @param {Node} node Node.
54661 * @param {string} value PropertyName value.
54662 * @private
54663 */
54664ol.format.WFS.writeOgcPropertyName_ = function(node, value) {
54665 ol.format.WFS.writeOgcExpression_('PropertyName', node, value);
54666};
54667
54668
54669/**
54670 * @param {Node} node Node.
54671 * @param {string} value PropertyName value.
54672 * @private
54673 */
54674ol.format.WFS.writeOgcLiteral_ = function(node, value) {
54675 ol.format.WFS.writeOgcExpression_('Literal', node, value);
54676};
54677
54678
54679/**
54680 * @param {Node} node Node.
54681 * @param {string} time PropertyName value.
54682 * @private
54683 */
54684ol.format.WFS.writeTimeInstant_ = function(node, time) {
54685 var timeInstant = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'TimeInstant');
54686 node.appendChild(timeInstant);
54687
54688 var timePosition = ol.xml.createElementNS(ol.format.GMLBase.GMLNS, 'timePosition');
54689 timeInstant.appendChild(timePosition);
54690 ol.format.XSD.writeStringTextNode(timePosition, time);
54691};
54692
54693
54694/**
54695 * @type {Object.<string, Object.<string, ol.XmlSerializer>>}
54696 * @private
54697 */
54698ol.format.WFS.GETFEATURE_SERIALIZERS_ = {
54699 'http://www.opengis.net/wfs': {
54700 'Query': ol.xml.makeChildAppender(ol.format.WFS.writeQuery_)
54701 },
54702 'http://www.opengis.net/ogc': {
54703 'During': ol.xml.makeChildAppender(ol.format.WFS.writeDuringFilter_),
54704 'And': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
54705 'Or': ol.xml.makeChildAppender(ol.format.WFS.writeLogicalFilter_),
54706 'Not': ol.xml.makeChildAppender(ol.format.WFS.writeNotFilter_),
54707 'BBOX': ol.xml.makeChildAppender(ol.format.WFS.writeBboxFilter_),
54708 'Intersects': ol.xml.makeChildAppender(ol.format.WFS.writeIntersectsFilter_),
54709 'Within': ol.xml.makeChildAppender(ol.format.WFS.writeWithinFilter_),
54710 'PropertyIsEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54711 'PropertyIsNotEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54712 'PropertyIsLessThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54713 'PropertyIsLessThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54714 'PropertyIsGreaterThan': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54715 'PropertyIsGreaterThanOrEqualTo': ol.xml.makeChildAppender(ol.format.WFS.writeComparisonFilter_),
54716 'PropertyIsNull': ol.xml.makeChildAppender(ol.format.WFS.writeIsNullFilter_),
54717 'PropertyIsBetween': ol.xml.makeChildAppender(ol.format.WFS.writeIsBetweenFilter_),
54718 'PropertyIsLike': ol.xml.makeChildAppender(ol.format.WFS.writeIsLikeFilter_)
54719 }
54720};
54721
54722
54723/**
54724 * Encode filter as WFS `Filter` and return the Node.
54725 *
54726 * @param {ol.format.filter.Filter} filter Filter.
54727 * @return {Node} Result.
54728 * @api
54729 */
54730ol.format.WFS.writeFilter = function(filter) {
54731 var child = ol.xml.createElementNS(ol.format.WFS.OGCNS, 'Filter');
54732 ol.format.WFS.writeFilterCondition_(child, filter, []);
54733 return child;
54734};
54735
54736
54737/**
54738 * @param {Node} node Node.
54739 * @param {Array.<string>} featureTypes Feature types.
54740 * @param {Array.<*>} objectStack Node stack.
54741 * @private
54742 */
54743ol.format.WFS.writeGetFeature_ = function(node, featureTypes, objectStack) {
54744 var context = /** @type {Object} */ (objectStack[objectStack.length - 1]);
54745 var item = /** @type {ol.XmlNodeStackItem} */ (ol.obj.assign({}, context));
54746 item.node = node;
54747 ol.xml.pushSerializeAndPop(item,
54748 ol.format.WFS.GETFEATURE_SERIALIZERS_,
54749 ol.xml.makeSimpleNodeFactory('Query'), featureTypes,
54750 objectStack);
54751};
54752
54753
54754/**
54755 * Encode format as WFS `GetFeature` and return the Node.
54756 *
54757 * @param {olx.format.WFSWriteGetFeatureOptions} options Options.
54758 * @return {Node} Result.
54759 * @api
54760 */
54761ol.format.WFS.prototype.writeGetFeature = function(options) {
54762 var node = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'GetFeature');
54763 node.setAttribute('service', 'WFS');
54764 node.setAttribute('version', '1.1.0');
54765 var filter;
54766 if (options) {
54767 if (options.handle) {
54768 node.setAttribute('handle', options.handle);
54769 }
54770 if (options.outputFormat) {
54771 node.setAttribute('outputFormat', options.outputFormat);
54772 }
54773 if (options.maxFeatures !== undefined) {
54774 node.setAttribute('maxFeatures', options.maxFeatures);
54775 }
54776 if (options.resultType) {
54777 node.setAttribute('resultType', options.resultType);
54778 }
54779 if (options.startIndex !== undefined) {
54780 node.setAttribute('startIndex', options.startIndex);
54781 }
54782 if (options.count !== undefined) {
54783 node.setAttribute('count', options.count);
54784 }
54785 filter = options.filter;
54786 if (options.bbox) {
54787 ol.asserts.assert(options.geometryName,
54788 12); // `options.geometryName` must also be provided when `options.bbox` is set
54789 var bbox = ol.format.filter.bbox(
54790 /** @type {string} */ (options.geometryName), options.bbox, options.srsName);
54791 if (filter) {
54792 // if bbox and filter are both set, combine the two into a single filter
54793 filter = ol.format.filter.and(filter, bbox);
54794 } else {
54795 filter = bbox;
54796 }
54797 }
54798 }
54799 ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
54800 'xsi:schemaLocation', this.schemaLocation_);
54801 /** @type {ol.XmlNodeStackItem} */
54802 var context = {
54803 node: node,
54804 'srsName': options.srsName,
54805 'featureNS': options.featureNS ? options.featureNS : this.featureNS_,
54806 'featurePrefix': options.featurePrefix,
54807 'geometryName': options.geometryName,
54808 'filter': filter,
54809 'propertyNames': options.propertyNames ? options.propertyNames : []
54810 };
54811 ol.asserts.assert(Array.isArray(options.featureTypes),
54812 11); // `options.featureTypes` should be an Array
54813 ol.format.WFS.writeGetFeature_(node, /** @type {!Array.<string>} */ (options.featureTypes), [context]);
54814 return node;
54815};
54816
54817
54818/**
54819 * Encode format as WFS `Transaction` and return the Node.
54820 *
54821 * @param {Array.<ol.Feature>} inserts The features to insert.
54822 * @param {Array.<ol.Feature>} updates The features to update.
54823 * @param {Array.<ol.Feature>} deletes The features to delete.
54824 * @param {olx.format.WFSWriteTransactionOptions} options Write options.
54825 * @return {Node} Result.
54826 * @api
54827 */
54828ol.format.WFS.prototype.writeTransaction = function(inserts, updates, deletes,
54829 options) {
54830 var objectStack = [];
54831 var node = ol.xml.createElementNS(ol.format.WFS.WFSNS, 'Transaction');
54832 var version = options.version ?
54833 options.version : ol.format.WFS.DEFAULT_VERSION;
54834 var gmlVersion = version === '1.0.0' ? 2 : 3;
54835 node.setAttribute('service', 'WFS');
54836 node.setAttribute('version', version);
54837 var baseObj;
54838 /** @type {ol.XmlNodeStackItem} */
54839 var obj;
54840 if (options) {
54841 baseObj = options.gmlOptions ? options.gmlOptions : {};
54842 if (options.handle) {
54843 node.setAttribute('handle', options.handle);
54844 }
54845 }
54846 var schemaLocation = ol.format.WFS.SCHEMA_LOCATIONS[version];
54847 ol.xml.setAttributeNS(node, 'http://www.w3.org/2001/XMLSchema-instance',
54848 'xsi:schemaLocation', schemaLocation);
54849 var featurePrefix = options.featurePrefix ? options.featurePrefix : ol.format.WFS.FEATURE_PREFIX;
54850 if (inserts) {
54851 obj = {node: node, 'featureNS': options.featureNS,
54852 'featureType': options.featureType, 'featurePrefix': featurePrefix,
54853 'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
54854 ol.obj.assign(obj, baseObj);
54855 ol.xml.pushSerializeAndPop(obj,
54856 ol.format.WFS.TRANSACTION_SERIALIZERS_,
54857 ol.xml.makeSimpleNodeFactory('Insert'), inserts,
54858 objectStack);
54859 }
54860 if (updates) {
54861 obj = {node: node, 'featureNS': options.featureNS,
54862 'featureType': options.featureType, 'featurePrefix': featurePrefix,
54863 'gmlVersion': gmlVersion, 'hasZ': options.hasZ, 'srsName': options.srsName};
54864 ol.obj.assign(obj, baseObj);
54865 ol.xml.pushSerializeAndPop(obj,
54866 ol.format.WFS.TRANSACTION_SERIALIZERS_,
54867 ol.xml.makeSimpleNodeFactory('Update'), updates,
54868 objectStack);
54869 }
54870 if (deletes) {
54871 ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
54872 'featureType': options.featureType, 'featurePrefix': featurePrefix,
54873 'gmlVersion': gmlVersion, 'srsName': options.srsName},
54874 ol.format.WFS.TRANSACTION_SERIALIZERS_,
54875 ol.xml.makeSimpleNodeFactory('Delete'), deletes,
54876 objectStack);
54877 }
54878 if (options.nativeElements) {
54879 ol.xml.pushSerializeAndPop({node: node, 'featureNS': options.featureNS,
54880 'featureType': options.featureType, 'featurePrefix': featurePrefix,
54881 'gmlVersion': gmlVersion, 'srsName': options.srsName},
54882 ol.format.WFS.TRANSACTION_SERIALIZERS_,
54883 ol.xml.makeSimpleNodeFactory('Native'), options.nativeElements,
54884 objectStack);
54885 }
54886 return node;
54887};
54888
54889
54890/**
54891 * Read the projection from a WFS source.
54892 *
54893 * @function
54894 * @param {Document|Node|Object|string} source Source.
54895 * @return {?ol.proj.Projection} Projection.
54896 * @api
54897 */
54898ol.format.WFS.prototype.readProjection;
54899
54900
54901/**
54902 * @inheritDoc
54903 */
54904ol.format.WFS.prototype.readProjectionFromDocument = function(doc) {
54905 for (var n = doc.firstChild; n; n = n.nextSibling) {
54906 if (n.nodeType == Node.ELEMENT_NODE) {
54907 return this.readProjectionFromNode(n);
54908 }
54909 }
54910 return null;
54911};
54912
54913
54914/**
54915 * @inheritDoc
54916 */
54917ol.format.WFS.prototype.readProjectionFromNode = function(node) {
54918 if (node.firstElementChild &&
54919 node.firstElementChild.firstElementChild) {
54920 node = node.firstElementChild.firstElementChild;
54921 for (var n = node.firstElementChild; n; n = n.nextElementSibling) {
54922 if (!(n.childNodes.length === 0 ||
54923 (n.childNodes.length === 1 &&
54924 n.firstChild.nodeType === 3))) {
54925 var objectStack = [{}];
54926 this.gmlFormat_.readGeometryElement(n, objectStack);
54927 return ol.proj.get(objectStack.pop().srsName);
54928 }
54929 }
54930 }
54931
54932 return null;
54933};
54934
54935goog.provide('ol.format.WKT');
54936
54937goog.require('ol');
54938goog.require('ol.Feature');
54939goog.require('ol.format.Feature');
54940goog.require('ol.format.TextFeature');
54941goog.require('ol.geom.GeometryCollection');
54942goog.require('ol.geom.GeometryType');
54943goog.require('ol.geom.GeometryLayout');
54944goog.require('ol.geom.LineString');
54945goog.require('ol.geom.MultiLineString');
54946goog.require('ol.geom.MultiPoint');
54947goog.require('ol.geom.MultiPolygon');
54948goog.require('ol.geom.Point');
54949goog.require('ol.geom.Polygon');
54950goog.require('ol.geom.SimpleGeometry');
54951
54952
54953/**
54954 * @classdesc
54955 * Geometry format for reading and writing data in the `WellKnownText` (WKT)
54956 * format.
54957 *
54958 * @constructor
54959 * @extends {ol.format.TextFeature}
54960 * @param {olx.format.WKTOptions=} opt_options Options.
54961 * @api
54962 */
54963ol.format.WKT = function(opt_options) {
54964
54965 var options = opt_options ? opt_options : {};
54966
54967 ol.format.TextFeature.call(this);
54968
54969 /**
54970 * Split GeometryCollection into multiple features.
54971 * @type {boolean}
54972 * @private
54973 */
54974 this.splitCollection_ = options.splitCollection !== undefined ?
54975 options.splitCollection : false;
54976
54977};
54978ol.inherits(ol.format.WKT, ol.format.TextFeature);
54979
54980
54981/**
54982 * @const
54983 * @type {string}
54984 */
54985ol.format.WKT.EMPTY = 'EMPTY';
54986
54987
54988/**
54989 * @const
54990 * @type {string}
54991 */
54992ol.format.WKT.Z = 'Z';
54993
54994
54995/**
54996 * @const
54997 * @type {string}
54998 */
54999ol.format.WKT.M = 'M';
55000
55001
55002/**
55003 * @const
55004 * @type {string}
55005 */
55006ol.format.WKT.ZM = 'ZM';
55007
55008
55009/**
55010 * @param {ol.geom.Point} geom Point geometry.
55011 * @return {string} Coordinates part of Point as WKT.
55012 * @private
55013 */
55014ol.format.WKT.encodePointGeometry_ = function(geom) {
55015 var coordinates = geom.getCoordinates();
55016 if (coordinates.length === 0) {
55017 return '';
55018 }
55019 return coordinates.join(' ');
55020};
55021
55022
55023/**
55024 * @param {ol.geom.MultiPoint} geom MultiPoint geometry.
55025 * @return {string} Coordinates part of MultiPoint as WKT.
55026 * @private
55027 */
55028ol.format.WKT.encodeMultiPointGeometry_ = function(geom) {
55029 var array = [];
55030 var components = geom.getPoints();
55031 for (var i = 0, ii = components.length; i < ii; ++i) {
55032 array.push('(' + ol.format.WKT.encodePointGeometry_(components[i]) + ')');
55033 }
55034 return array.join(',');
55035};
55036
55037
55038/**
55039 * @param {ol.geom.GeometryCollection} geom GeometryCollection geometry.
55040 * @return {string} Coordinates part of GeometryCollection as WKT.
55041 * @private
55042 */
55043ol.format.WKT.encodeGeometryCollectionGeometry_ = function(geom) {
55044 var array = [];
55045 var geoms = geom.getGeometries();
55046 for (var i = 0, ii = geoms.length; i < ii; ++i) {
55047 array.push(ol.format.WKT.encode_(geoms[i]));
55048 }
55049 return array.join(',');
55050};
55051
55052
55053/**
55054 * @param {ol.geom.LineString|ol.geom.LinearRing} geom LineString geometry.
55055 * @return {string} Coordinates part of LineString as WKT.
55056 * @private
55057 */
55058ol.format.WKT.encodeLineStringGeometry_ = function(geom) {
55059 var coordinates = geom.getCoordinates();
55060 var array = [];
55061 for (var i = 0, ii = coordinates.length; i < ii; ++i) {
55062 array.push(coordinates[i].join(' '));
55063 }
55064 return array.join(',');
55065};
55066
55067
55068/**
55069 * @param {ol.geom.MultiLineString} geom MultiLineString geometry.
55070 * @return {string} Coordinates part of MultiLineString as WKT.
55071 * @private
55072 */
55073ol.format.WKT.encodeMultiLineStringGeometry_ = function(geom) {
55074 var array = [];
55075 var components = geom.getLineStrings();
55076 for (var i = 0, ii = components.length; i < ii; ++i) {
55077 array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
55078 components[i]) + ')');
55079 }
55080 return array.join(',');
55081};
55082
55083
55084/**
55085 * @param {ol.geom.Polygon} geom Polygon geometry.
55086 * @return {string} Coordinates part of Polygon as WKT.
55087 * @private
55088 */
55089ol.format.WKT.encodePolygonGeometry_ = function(geom) {
55090 var array = [];
55091 var rings = geom.getLinearRings();
55092 for (var i = 0, ii = rings.length; i < ii; ++i) {
55093 array.push('(' + ol.format.WKT.encodeLineStringGeometry_(
55094 rings[i]) + ')');
55095 }
55096 return array.join(',');
55097};
55098
55099
55100/**
55101 * @param {ol.geom.MultiPolygon} geom MultiPolygon geometry.
55102 * @return {string} Coordinates part of MultiPolygon as WKT.
55103 * @private
55104 */
55105ol.format.WKT.encodeMultiPolygonGeometry_ = function(geom) {
55106 var array = [];
55107 var components = geom.getPolygons();
55108 for (var i = 0, ii = components.length; i < ii; ++i) {
55109 array.push('(' + ol.format.WKT.encodePolygonGeometry_(
55110 components[i]) + ')');
55111 }
55112 return array.join(',');
55113};
55114
55115/**
55116 * @param {ol.geom.SimpleGeometry} geom SimpleGeometry geometry.
55117 * @return {string} Potential dimensional information for WKT type.
55118 * @private
55119 */
55120ol.format.WKT.encodeGeometryLayout_ = function(geom) {
55121 var layout = geom.getLayout();
55122 var dimInfo = '';
55123 if (layout === ol.geom.GeometryLayout.XYZ || layout === ol.geom.GeometryLayout.XYZM) {
55124 dimInfo += ol.format.WKT.Z;
55125 }
55126 if (layout === ol.geom.GeometryLayout.XYM || layout === ol.geom.GeometryLayout.XYZM) {
55127 dimInfo += ol.format.WKT.M;
55128 }
55129 return dimInfo;
55130};
55131
55132
55133/**
55134 * Encode a geometry as WKT.
55135 * @param {ol.geom.Geometry} geom The geometry to encode.
55136 * @return {string} WKT string for the geometry.
55137 * @private
55138 */
55139ol.format.WKT.encode_ = function(geom) {
55140 var type = geom.getType();
55141 var geometryEncoder = ol.format.WKT.GeometryEncoder_[type];
55142 var enc = geometryEncoder(geom);
55143 type = type.toUpperCase();
55144 if (geom instanceof ol.geom.SimpleGeometry) {
55145 var dimInfo = ol.format.WKT.encodeGeometryLayout_(geom);
55146 if (dimInfo.length > 0) {
55147 type += ' ' + dimInfo;
55148 }
55149 }
55150 if (enc.length === 0) {
55151 return type + ' ' + ol.format.WKT.EMPTY;
55152 }
55153 return type + '(' + enc + ')';
55154};
55155
55156
55157/**
55158 * @const
55159 * @type {Object.<string, function(ol.geom.Geometry): string>}
55160 * @private
55161 */
55162ol.format.WKT.GeometryEncoder_ = {
55163 'Point': ol.format.WKT.encodePointGeometry_,
55164 'LineString': ol.format.WKT.encodeLineStringGeometry_,
55165 'Polygon': ol.format.WKT.encodePolygonGeometry_,
55166 'MultiPoint': ol.format.WKT.encodeMultiPointGeometry_,
55167 'MultiLineString': ol.format.WKT.encodeMultiLineStringGeometry_,
55168 'MultiPolygon': ol.format.WKT.encodeMultiPolygonGeometry_,
55169 'GeometryCollection': ol.format.WKT.encodeGeometryCollectionGeometry_
55170};
55171
55172
55173/**
55174 * Parse a WKT string.
55175 * @param {string} wkt WKT string.
55176 * @return {ol.geom.Geometry|undefined}
55177 * The geometry created.
55178 * @private
55179 */
55180ol.format.WKT.prototype.parse_ = function(wkt) {
55181 var lexer = new ol.format.WKT.Lexer(wkt);
55182 var parser = new ol.format.WKT.Parser(lexer);
55183 return parser.parse();
55184};
55185
55186
55187/**
55188 * Read a feature from a WKT source.
55189 *
55190 * @function
55191 * @param {Document|Node|Object|string} source Source.
55192 * @param {olx.format.ReadOptions=} opt_options Read options.
55193 * @return {ol.Feature} Feature.
55194 * @api
55195 */
55196ol.format.WKT.prototype.readFeature;
55197
55198
55199/**
55200 * @inheritDoc
55201 */
55202ol.format.WKT.prototype.readFeatureFromText = function(text, opt_options) {
55203 var geom = this.readGeometryFromText(text, opt_options);
55204 if (geom) {
55205 var feature = new ol.Feature();
55206 feature.setGeometry(geom);
55207 return feature;
55208 }
55209 return null;
55210};
55211
55212
55213/**
55214 * Read all features from a WKT source.
55215 *
55216 * @function
55217 * @param {Document|Node|Object|string} source Source.
55218 * @param {olx.format.ReadOptions=} opt_options Read options.
55219 * @return {Array.<ol.Feature>} Features.
55220 * @api
55221 */
55222ol.format.WKT.prototype.readFeatures;
55223
55224
55225/**
55226 * @inheritDoc
55227 */
55228ol.format.WKT.prototype.readFeaturesFromText = function(text, opt_options) {
55229 var geometries = [];
55230 var geometry = this.readGeometryFromText(text, opt_options);
55231 if (this.splitCollection_ &&
55232 geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
55233 geometries = (/** @type {ol.geom.GeometryCollection} */ (geometry))
55234 .getGeometriesArray();
55235 } else {
55236 geometries = [geometry];
55237 }
55238 var feature, features = [];
55239 for (var i = 0, ii = geometries.length; i < ii; ++i) {
55240 feature = new ol.Feature();
55241 feature.setGeometry(geometries[i]);
55242 features.push(feature);
55243 }
55244 return features;
55245};
55246
55247
55248/**
55249 * Read a single geometry from a WKT source.
55250 *
55251 * @function
55252 * @param {Document|Node|Object|string} source Source.
55253 * @param {olx.format.ReadOptions=} opt_options Read options.
55254 * @return {ol.geom.Geometry} Geometry.
55255 * @api
55256 */
55257ol.format.WKT.prototype.readGeometry;
55258
55259
55260/**
55261 * @inheritDoc
55262 */
55263ol.format.WKT.prototype.readGeometryFromText = function(text, opt_options) {
55264 var geometry = this.parse_(text);
55265 if (geometry) {
55266 return /** @type {ol.geom.Geometry} */ (
55267 ol.format.Feature.transformWithOptions(geometry, false, opt_options));
55268 } else {
55269 return null;
55270 }
55271};
55272
55273
55274/**
55275 * Encode a feature as a WKT string.
55276 *
55277 * @function
55278 * @param {ol.Feature} feature Feature.
55279 * @param {olx.format.WriteOptions=} opt_options Write options.
55280 * @return {string} WKT string.
55281 * @api
55282 */
55283ol.format.WKT.prototype.writeFeature;
55284
55285
55286/**
55287 * @inheritDoc
55288 */
55289ol.format.WKT.prototype.writeFeatureText = function(feature, opt_options) {
55290 var geometry = feature.getGeometry();
55291 if (geometry) {
55292 return this.writeGeometryText(geometry, opt_options);
55293 }
55294 return '';
55295};
55296
55297
55298/**
55299 * Encode an array of features as a WKT string.
55300 *
55301 * @function
55302 * @param {Array.<ol.Feature>} features Features.
55303 * @param {olx.format.WriteOptions=} opt_options Write options.
55304 * @return {string} WKT string.
55305 * @api
55306 */
55307ol.format.WKT.prototype.writeFeatures;
55308
55309
55310/**
55311 * @inheritDoc
55312 */
55313ol.format.WKT.prototype.writeFeaturesText = function(features, opt_options) {
55314 if (features.length == 1) {
55315 return this.writeFeatureText(features[0], opt_options);
55316 }
55317 var geometries = [];
55318 for (var i = 0, ii = features.length; i < ii; ++i) {
55319 geometries.push(features[i].getGeometry());
55320 }
55321 var collection = new ol.geom.GeometryCollection(geometries);
55322 return this.writeGeometryText(collection, opt_options);
55323};
55324
55325
55326/**
55327 * Write a single geometry as a WKT string.
55328 *
55329 * @function
55330 * @param {ol.geom.Geometry} geometry Geometry.
55331 * @return {string} WKT string.
55332 * @api
55333 */
55334ol.format.WKT.prototype.writeGeometry;
55335
55336
55337/**
55338 * @inheritDoc
55339 */
55340ol.format.WKT.prototype.writeGeometryText = function(geometry, opt_options) {
55341 return ol.format.WKT.encode_(/** @type {ol.geom.Geometry} */ (
55342 ol.format.Feature.transformWithOptions(geometry, true, opt_options)));
55343};
55344
55345
55346/**
55347 * @const
55348 * @enum {number}
55349 * @private
55350 */
55351ol.format.WKT.TokenType_ = {
55352 TEXT: 1,
55353 LEFT_PAREN: 2,
55354 RIGHT_PAREN: 3,
55355 NUMBER: 4,
55356 COMMA: 5,
55357 EOF: 6
55358};
55359
55360
55361/**
55362 * Class to tokenize a WKT string.
55363 * @param {string} wkt WKT string.
55364 * @constructor
55365 * @protected
55366 */
55367ol.format.WKT.Lexer = function(wkt) {
55368
55369 /**
55370 * @type {string}
55371 */
55372 this.wkt = wkt;
55373
55374 /**
55375 * @type {number}
55376 * @private
55377 */
55378 this.index_ = -1;
55379};
55380
55381
55382/**
55383 * @param {string} c Character.
55384 * @return {boolean} Whether the character is alphabetic.
55385 * @private
55386 */
55387ol.format.WKT.Lexer.prototype.isAlpha_ = function(c) {
55388 return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
55389};
55390
55391
55392/**
55393 * @param {string} c Character.
55394 * @param {boolean=} opt_decimal Whether the string number
55395 * contains a dot, i.e. is a decimal number.
55396 * @return {boolean} Whether the character is numeric.
55397 * @private
55398 */
55399ol.format.WKT.Lexer.prototype.isNumeric_ = function(c, opt_decimal) {
55400 var decimal = opt_decimal !== undefined ? opt_decimal : false;
55401 return c >= '0' && c <= '9' || c == '.' && !decimal;
55402};
55403
55404
55405/**
55406 * @param {string} c Character.
55407 * @return {boolean} Whether the character is whitespace.
55408 * @private
55409 */
55410ol.format.WKT.Lexer.prototype.isWhiteSpace_ = function(c) {
55411 return c == ' ' || c == '\t' || c == '\r' || c == '\n';
55412};
55413
55414
55415/**
55416 * @return {string} Next string character.
55417 * @private
55418 */
55419ol.format.WKT.Lexer.prototype.nextChar_ = function() {
55420 return this.wkt.charAt(++this.index_);
55421};
55422
55423
55424/**
55425 * Fetch and return the next token.
55426 * @return {!ol.WKTToken} Next string token.
55427 */
55428ol.format.WKT.Lexer.prototype.nextToken = function() {
55429 var c = this.nextChar_();
55430 var token = {position: this.index_, value: c};
55431
55432 if (c == '(') {
55433 token.type = ol.format.WKT.TokenType_.LEFT_PAREN;
55434 } else if (c == ',') {
55435 token.type = ol.format.WKT.TokenType_.COMMA;
55436 } else if (c == ')') {
55437 token.type = ol.format.WKT.TokenType_.RIGHT_PAREN;
55438 } else if (this.isNumeric_(c) || c == '-') {
55439 token.type = ol.format.WKT.TokenType_.NUMBER;
55440 token.value = this.readNumber_();
55441 } else if (this.isAlpha_(c)) {
55442 token.type = ol.format.WKT.TokenType_.TEXT;
55443 token.value = this.readText_();
55444 } else if (this.isWhiteSpace_(c)) {
55445 return this.nextToken();
55446 } else if (c === '') {
55447 token.type = ol.format.WKT.TokenType_.EOF;
55448 } else {
55449 throw new Error('Unexpected character: ' + c);
55450 }
55451
55452 return token;
55453};
55454
55455
55456/**
55457 * @return {number} Numeric token value.
55458 * @private
55459 */
55460ol.format.WKT.Lexer.prototype.readNumber_ = function() {
55461 var c, index = this.index_;
55462 var decimal = false;
55463 var scientificNotation = false;
55464 do {
55465 if (c == '.') {
55466 decimal = true;
55467 } else if (c == 'e' || c == 'E') {
55468 scientificNotation = true;
55469 }
55470 c = this.nextChar_();
55471 } while (
55472 this.isNumeric_(c, decimal) ||
55473 // if we haven't detected a scientific number before, 'e' or 'E'
55474 // hint that we should continue to read
55475 !scientificNotation && (c == 'e' || c == 'E') ||
55476 // once we know that we have a scientific number, both '-' and '+'
55477 // are allowed
55478 scientificNotation && (c == '-' || c == '+')
55479 );
55480 return parseFloat(this.wkt.substring(index, this.index_--));
55481};
55482
55483
55484/**
55485 * @return {string} String token value.
55486 * @private
55487 */
55488ol.format.WKT.Lexer.prototype.readText_ = function() {
55489 var c, index = this.index_;
55490 do {
55491 c = this.nextChar_();
55492 } while (this.isAlpha_(c));
55493 return this.wkt.substring(index, this.index_--).toUpperCase();
55494};
55495
55496
55497/**
55498 * Class to parse the tokens from the WKT string.
55499 * @param {ol.format.WKT.Lexer} lexer The lexer.
55500 * @constructor
55501 * @protected
55502 */
55503ol.format.WKT.Parser = function(lexer) {
55504
55505 /**
55506 * @type {ol.format.WKT.Lexer}
55507 * @private
55508 */
55509 this.lexer_ = lexer;
55510
55511 /**
55512 * @type {ol.WKTToken}
55513 * @private
55514 */
55515 this.token_;
55516
55517 /**
55518 * @type {ol.geom.GeometryLayout}
55519 * @private
55520 */
55521 this.layout_ = ol.geom.GeometryLayout.XY;
55522};
55523
55524
55525/**
55526 * Fetch the next token form the lexer and replace the active token.
55527 * @private
55528 */
55529ol.format.WKT.Parser.prototype.consume_ = function() {
55530 this.token_ = this.lexer_.nextToken();
55531};
55532
55533/**
55534 * Tests if the given type matches the type of the current token.
55535 * @param {ol.format.WKT.TokenType_} type Token type.
55536 * @return {boolean} Whether the token matches the given type.
55537 */
55538ol.format.WKT.Parser.prototype.isTokenType = function(type) {
55539 var isMatch = this.token_.type == type;
55540 return isMatch;
55541};
55542
55543
55544/**
55545 * If the given type matches the current token, consume it.
55546 * @param {ol.format.WKT.TokenType_} type Token type.
55547 * @return {boolean} Whether the token matches the given type.
55548 */
55549ol.format.WKT.Parser.prototype.match = function(type) {
55550 var isMatch = this.isTokenType(type);
55551 if (isMatch) {
55552 this.consume_();
55553 }
55554 return isMatch;
55555};
55556
55557
55558/**
55559 * Try to parse the tokens provided by the lexer.
55560 * @return {ol.geom.Geometry} The geometry.
55561 */
55562ol.format.WKT.Parser.prototype.parse = function() {
55563 this.consume_();
55564 var geometry = this.parseGeometry_();
55565 return geometry;
55566};
55567
55568
55569/**
55570 * Try to parse the dimensional info.
55571 * @return {ol.geom.GeometryLayout} The layout.
55572 * @private
55573 */
55574ol.format.WKT.Parser.prototype.parseGeometryLayout_ = function() {
55575 var layout = ol.geom.GeometryLayout.XY;
55576 var dimToken = this.token_;
55577 if (this.isTokenType(ol.format.WKT.TokenType_.TEXT)) {
55578 var dimInfo = dimToken.value;
55579 if (dimInfo === ol.format.WKT.Z) {
55580 layout = ol.geom.GeometryLayout.XYZ;
55581 } else if (dimInfo === ol.format.WKT.M) {
55582 layout = ol.geom.GeometryLayout.XYM;
55583 } else if (dimInfo === ol.format.WKT.ZM) {
55584 layout = ol.geom.GeometryLayout.XYZM;
55585 }
55586 if (layout !== ol.geom.GeometryLayout.XY) {
55587 this.consume_();
55588 }
55589 }
55590 return layout;
55591};
55592
55593
55594/**
55595 * @return {!ol.geom.Geometry} The geometry.
55596 * @private
55597 */
55598ol.format.WKT.Parser.prototype.parseGeometry_ = function() {
55599 var token = this.token_;
55600 if (this.match(ol.format.WKT.TokenType_.TEXT)) {
55601 var geomType = token.value;
55602 this.layout_ = this.parseGeometryLayout_();
55603 if (geomType == ol.geom.GeometryType.GEOMETRY_COLLECTION.toUpperCase()) {
55604 var geometries = this.parseGeometryCollectionText_();
55605 return new ol.geom.GeometryCollection(geometries);
55606 } else {
55607 var parser = ol.format.WKT.Parser.GeometryParser_[geomType];
55608 var ctor = ol.format.WKT.Parser.GeometryConstructor_[geomType];
55609 if (!parser || !ctor) {
55610 throw new Error('Invalid geometry type: ' + geomType);
55611 }
55612 var coordinates = parser.call(this);
55613 return new ctor(coordinates, this.layout_);
55614 }
55615 }
55616 throw new Error(this.formatErrorMessage_());
55617};
55618
55619
55620/**
55621 * @return {!Array.<ol.geom.Geometry>} A collection of geometries.
55622 * @private
55623 */
55624ol.format.WKT.Parser.prototype.parseGeometryCollectionText_ = function() {
55625 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55626 var geometries = [];
55627 do {
55628 geometries.push(this.parseGeometry_());
55629 } while (this.match(ol.format.WKT.TokenType_.COMMA));
55630 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55631 return geometries;
55632 }
55633 } else if (this.isEmptyGeometry_()) {
55634 return [];
55635 }
55636 throw new Error(this.formatErrorMessage_());
55637};
55638
55639
55640/**
55641 * @return {Array.<number>} All values in a point.
55642 * @private
55643 */
55644ol.format.WKT.Parser.prototype.parsePointText_ = function() {
55645 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55646 var coordinates = this.parsePoint_();
55647 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55648 return coordinates;
55649 }
55650 } else if (this.isEmptyGeometry_()) {
55651 return null;
55652 }
55653 throw new Error(this.formatErrorMessage_());
55654};
55655
55656
55657/**
55658 * @return {!Array.<!Array.<number>>} All points in a linestring.
55659 * @private
55660 */
55661ol.format.WKT.Parser.prototype.parseLineStringText_ = function() {
55662 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55663 var coordinates = this.parsePointList_();
55664 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55665 return coordinates;
55666 }
55667 } else if (this.isEmptyGeometry_()) {
55668 return [];
55669 }
55670 throw new Error(this.formatErrorMessage_());
55671};
55672
55673
55674/**
55675 * @return {!Array.<!Array.<number>>} All points in a polygon.
55676 * @private
55677 */
55678ol.format.WKT.Parser.prototype.parsePolygonText_ = function() {
55679 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55680 var coordinates = this.parseLineStringTextList_();
55681 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55682 return coordinates;
55683 }
55684 } else if (this.isEmptyGeometry_()) {
55685 return [];
55686 }
55687 throw new Error(this.formatErrorMessage_());
55688};
55689
55690
55691/**
55692 * @return {!Array.<!Array.<number>>} All points in a multipoint.
55693 * @private
55694 */
55695ol.format.WKT.Parser.prototype.parseMultiPointText_ = function() {
55696 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55697 var coordinates;
55698 if (this.token_.type == ol.format.WKT.TokenType_.LEFT_PAREN) {
55699 coordinates = this.parsePointTextList_();
55700 } else {
55701 coordinates = this.parsePointList_();
55702 }
55703 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55704 return coordinates;
55705 }
55706 } else if (this.isEmptyGeometry_()) {
55707 return [];
55708 }
55709 throw new Error(this.formatErrorMessage_());
55710};
55711
55712
55713/**
55714 * @return {!Array.<!Array.<number>>} All linestring points
55715 * in a multilinestring.
55716 * @private
55717 */
55718ol.format.WKT.Parser.prototype.parseMultiLineStringText_ = function() {
55719 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55720 var coordinates = this.parseLineStringTextList_();
55721 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55722 return coordinates;
55723 }
55724 } else if (this.isEmptyGeometry_()) {
55725 return [];
55726 }
55727 throw new Error(this.formatErrorMessage_());
55728};
55729
55730
55731/**
55732 * @return {!Array.<!Array.<number>>} All polygon points in a multipolygon.
55733 * @private
55734 */
55735ol.format.WKT.Parser.prototype.parseMultiPolygonText_ = function() {
55736 if (this.match(ol.format.WKT.TokenType_.LEFT_PAREN)) {
55737 var coordinates = this.parsePolygonTextList_();
55738 if (this.match(ol.format.WKT.TokenType_.RIGHT_PAREN)) {
55739 return coordinates;
55740 }
55741 } else if (this.isEmptyGeometry_()) {
55742 return [];
55743 }
55744 throw new Error(this.formatErrorMessage_());
55745};
55746
55747
55748/**
55749 * @return {!Array.<number>} A point.
55750 * @private
55751 */
55752ol.format.WKT.Parser.prototype.parsePoint_ = function() {
55753 var coordinates = [];
55754 var dimensions = this.layout_.length;
55755 for (var i = 0; i < dimensions; ++i) {
55756 var token = this.token_;
55757 if (this.match(ol.format.WKT.TokenType_.NUMBER)) {
55758 coordinates.push(token.value);
55759 } else {
55760 break;
55761 }
55762 }
55763 if (coordinates.length == dimensions) {
55764 return coordinates;
55765 }
55766 throw new Error(this.formatErrorMessage_());
55767};
55768
55769
55770/**
55771 * @return {!Array.<!Array.<number>>} An array of points.
55772 * @private
55773 */
55774ol.format.WKT.Parser.prototype.parsePointList_ = function() {
55775 var coordinates = [this.parsePoint_()];
55776 while (this.match(ol.format.WKT.TokenType_.COMMA)) {
55777 coordinates.push(this.parsePoint_());
55778 }
55779 return coordinates;
55780};
55781
55782
55783/**
55784 * @return {!Array.<!Array.<number>>} An array of points.
55785 * @private
55786 */
55787ol.format.WKT.Parser.prototype.parsePointTextList_ = function() {
55788 var coordinates = [this.parsePointText_()];
55789 while (this.match(ol.format.WKT.TokenType_.COMMA)) {
55790 coordinates.push(this.parsePointText_());
55791 }
55792 return coordinates;
55793};
55794
55795
55796/**
55797 * @return {!Array.<!Array.<number>>} An array of points.
55798 * @private
55799 */
55800ol.format.WKT.Parser.prototype.parseLineStringTextList_ = function() {
55801 var coordinates = [this.parseLineStringText_()];
55802 while (this.match(ol.format.WKT.TokenType_.COMMA)) {
55803 coordinates.push(this.parseLineStringText_());
55804 }
55805 return coordinates;
55806};
55807
55808
55809/**
55810 * @return {!Array.<!Array.<number>>} An array of points.
55811 * @private
55812 */
55813ol.format.WKT.Parser.prototype.parsePolygonTextList_ = function() {
55814 var coordinates = [this.parsePolygonText_()];
55815 while (this.match(ol.format.WKT.TokenType_.COMMA)) {
55816 coordinates.push(this.parsePolygonText_());
55817 }
55818 return coordinates;
55819};
55820
55821
55822/**
55823 * @return {boolean} Whether the token implies an empty geometry.
55824 * @private
55825 */
55826ol.format.WKT.Parser.prototype.isEmptyGeometry_ = function() {
55827 var isEmpty = this.isTokenType(ol.format.WKT.TokenType_.TEXT) &&
55828 this.token_.value == ol.format.WKT.EMPTY;
55829 if (isEmpty) {
55830 this.consume_();
55831 }
55832 return isEmpty;
55833};
55834
55835
55836/**
55837 * Create an error message for an unexpected token error.
55838 * @return {string} Error message.
55839 * @private
55840 */
55841ol.format.WKT.Parser.prototype.formatErrorMessage_ = function() {
55842 return 'Unexpected `' + this.token_.value + '` at position ' +
55843 this.token_.position + ' in `' + this.lexer_.wkt + '`';
55844};
55845
55846
55847/**
55848 * @enum {function (new:ol.geom.Geometry, Array, ol.geom.GeometryLayout)}
55849 * @private
55850 */
55851ol.format.WKT.Parser.GeometryConstructor_ = {
55852 'POINT': ol.geom.Point,
55853 'LINESTRING': ol.geom.LineString,
55854 'POLYGON': ol.geom.Polygon,
55855 'MULTIPOINT': ol.geom.MultiPoint,
55856 'MULTILINESTRING': ol.geom.MultiLineString,
55857 'MULTIPOLYGON': ol.geom.MultiPolygon
55858};
55859
55860
55861/**
55862 * @enum {(function(): Array)}
55863 * @private
55864 */
55865ol.format.WKT.Parser.GeometryParser_ = {
55866 'POINT': ol.format.WKT.Parser.prototype.parsePointText_,
55867 'LINESTRING': ol.format.WKT.Parser.prototype.parseLineStringText_,
55868 'POLYGON': ol.format.WKT.Parser.prototype.parsePolygonText_,
55869 'MULTIPOINT': ol.format.WKT.Parser.prototype.parseMultiPointText_,
55870 'MULTILINESTRING': ol.format.WKT.Parser.prototype.parseMultiLineStringText_,
55871 'MULTIPOLYGON': ol.format.WKT.Parser.prototype.parseMultiPolygonText_
55872};
55873
55874goog.provide('ol.format.WMSCapabilities');
55875
55876goog.require('ol');
55877goog.require('ol.format.XLink');
55878goog.require('ol.format.XML');
55879goog.require('ol.format.XSD');
55880goog.require('ol.xml');
55881
55882
55883/**
55884 * @classdesc
55885 * Format for reading WMS capabilities data
55886 *
55887 * @constructor
55888 * @extends {ol.format.XML}
55889 * @api
55890 */
55891ol.format.WMSCapabilities = function() {
55892
55893 ol.format.XML.call(this);
55894
55895 /**
55896 * @type {string|undefined}
55897 */
55898 this.version = undefined;
55899};
55900ol.inherits(ol.format.WMSCapabilities, ol.format.XML);
55901
55902
55903/**
55904 * Read a WMS capabilities document.
55905 *
55906 * @function
55907 * @param {Document|Node|string} source The XML source.
55908 * @return {Object} An object representing the WMS capabilities.
55909 * @api
55910 */
55911ol.format.WMSCapabilities.prototype.read;
55912
55913
55914/**
55915 * @inheritDoc
55916 */
55917ol.format.WMSCapabilities.prototype.readFromDocument = function(doc) {
55918 for (var n = doc.firstChild; n; n = n.nextSibling) {
55919 if (n.nodeType == Node.ELEMENT_NODE) {
55920 return this.readFromNode(n);
55921 }
55922 }
55923 return null;
55924};
55925
55926
55927/**
55928 * @inheritDoc
55929 */
55930ol.format.WMSCapabilities.prototype.readFromNode = function(node) {
55931 this.version = node.getAttribute('version').trim();
55932 var wmsCapabilityObject = ol.xml.pushParseAndPop({
55933 'version': this.version
55934 }, ol.format.WMSCapabilities.PARSERS_, node, []);
55935 return wmsCapabilityObject ? wmsCapabilityObject : null;
55936};
55937
55938
55939/**
55940 * @private
55941 * @param {Node} node Node.
55942 * @param {Array.<*>} objectStack Object stack.
55943 * @return {Object|undefined} Attribution object.
55944 */
55945ol.format.WMSCapabilities.readAttribution_ = function(node, objectStack) {
55946 return ol.xml.pushParseAndPop(
55947 {}, ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_, node, objectStack);
55948};
55949
55950
55951/**
55952 * @private
55953 * @param {Node} node Node.
55954 * @param {Array.<*>} objectStack Object stack.
55955 * @return {Object} Bounding box object.
55956 */
55957ol.format.WMSCapabilities.readBoundingBox_ = function(node, objectStack) {
55958 var extent = [
55959 ol.format.XSD.readDecimalString(node.getAttribute('minx')),
55960 ol.format.XSD.readDecimalString(node.getAttribute('miny')),
55961 ol.format.XSD.readDecimalString(node.getAttribute('maxx')),
55962 ol.format.XSD.readDecimalString(node.getAttribute('maxy'))
55963 ];
55964
55965 var resolutions = [
55966 ol.format.XSD.readDecimalString(node.getAttribute('resx')),
55967 ol.format.XSD.readDecimalString(node.getAttribute('resy'))
55968 ];
55969
55970 return {
55971 'crs': node.getAttribute('CRS'),
55972 'extent': extent,
55973 'res': resolutions
55974 };
55975};
55976
55977
55978/**
55979 * @private
55980 * @param {Node} node Node.
55981 * @param {Array.<*>} objectStack Object stack.
55982 * @return {ol.Extent|undefined} Bounding box object.
55983 */
55984ol.format.WMSCapabilities.readEXGeographicBoundingBox_ = function(node, objectStack) {
55985 var geographicBoundingBox = ol.xml.pushParseAndPop(
55986 {},
55987 ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_,
55988 node, objectStack);
55989 if (!geographicBoundingBox) {
55990 return undefined;
55991 }
55992 var westBoundLongitude = /** @type {number|undefined} */
55993 (geographicBoundingBox['westBoundLongitude']);
55994 var southBoundLatitude = /** @type {number|undefined} */
55995 (geographicBoundingBox['southBoundLatitude']);
55996 var eastBoundLongitude = /** @type {number|undefined} */
55997 (geographicBoundingBox['eastBoundLongitude']);
55998 var northBoundLatitude = /** @type {number|undefined} */
55999 (geographicBoundingBox['northBoundLatitude']);
56000 if (westBoundLongitude === undefined || southBoundLatitude === undefined ||
56001 eastBoundLongitude === undefined || northBoundLatitude === undefined) {
56002 return undefined;
56003 }
56004 return [
56005 westBoundLongitude, southBoundLatitude,
56006 eastBoundLongitude, northBoundLatitude
56007 ];
56008};
56009
56010
56011/**
56012 * @param {Node} node Node.
56013 * @param {Array.<*>} objectStack Object stack.
56014 * @private
56015 * @return {Object|undefined} Capability object.
56016 */
56017ol.format.WMSCapabilities.readCapability_ = function(node, objectStack) {
56018 return ol.xml.pushParseAndPop(
56019 {}, ol.format.WMSCapabilities.CAPABILITY_PARSERS_, node, objectStack);
56020};
56021
56022
56023/**
56024 * @param {Node} node Node.
56025 * @param {Array.<*>} objectStack Object stack.
56026 * @private
56027 * @return {Object|undefined} Service object.
56028 */
56029ol.format.WMSCapabilities.readService_ = function(node, objectStack) {
56030 return ol.xml.pushParseAndPop(
56031 {}, ol.format.WMSCapabilities.SERVICE_PARSERS_, node, objectStack);
56032};
56033
56034
56035/**
56036 * @param {Node} node Node.
56037 * @param {Array.<*>} objectStack Object stack.
56038 * @private
56039 * @return {Object|undefined} Contact information object.
56040 */
56041ol.format.WMSCapabilities.readContactInformation_ = function(node, objectStack) {
56042 return ol.xml.pushParseAndPop(
56043 {}, ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_,
56044 node, objectStack);
56045};
56046
56047
56048/**
56049 * @param {Node} node Node.
56050 * @param {Array.<*>} objectStack Object stack.
56051 * @private
56052 * @return {Object|undefined} Contact person object.
56053 */
56054ol.format.WMSCapabilities.readContactPersonPrimary_ = function(node, objectStack) {
56055 return ol.xml.pushParseAndPop(
56056 {}, ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_,
56057 node, objectStack);
56058};
56059
56060
56061/**
56062 * @param {Node} node Node.
56063 * @param {Array.<*>} objectStack Object stack.
56064 * @private
56065 * @return {Object|undefined} Contact address object.
56066 */
56067ol.format.WMSCapabilities.readContactAddress_ = function(node, objectStack) {
56068 return ol.xml.pushParseAndPop(
56069 {}, ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_,
56070 node, objectStack);
56071};
56072
56073
56074/**
56075 * @param {Node} node Node.
56076 * @param {Array.<*>} objectStack Object stack.
56077 * @private
56078 * @return {Array.<string>|undefined} Format array.
56079 */
56080ol.format.WMSCapabilities.readException_ = function(node, objectStack) {
56081 return ol.xml.pushParseAndPop(
56082 [], ol.format.WMSCapabilities.EXCEPTION_PARSERS_, node, objectStack);
56083};
56084
56085
56086/**
56087 * @param {Node} node Node.
56088 * @param {Array.<*>} objectStack Object stack.
56089 * @private
56090 * @return {Object|undefined} Layer object.
56091 */
56092ol.format.WMSCapabilities.readCapabilityLayer_ = function(node, objectStack) {
56093 return ol.xml.pushParseAndPop(
56094 {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);
56095};
56096
56097
56098/**
56099 * @private
56100 * @param {Node} node Node.
56101 * @param {Array.<*>} objectStack Object stack.
56102 * @return {Object|undefined} Layer object.
56103 */
56104ol.format.WMSCapabilities.readLayer_ = function(node, objectStack) {
56105 var parentLayerObject = /** @type {Object.<string,*>} */
56106 (objectStack[objectStack.length - 1]);
56107
56108 var layerObject = ol.xml.pushParseAndPop(
56109 {}, ol.format.WMSCapabilities.LAYER_PARSERS_, node, objectStack);
56110
56111 if (!layerObject) {
56112 return undefined;
56113 }
56114 var queryable =
56115 ol.format.XSD.readBooleanString(node.getAttribute('queryable'));
56116 if (queryable === undefined) {
56117 queryable = parentLayerObject['queryable'];
56118 }
56119 layerObject['queryable'] = queryable !== undefined ? queryable : false;
56120
56121 var cascaded = ol.format.XSD.readNonNegativeIntegerString(
56122 node.getAttribute('cascaded'));
56123 if (cascaded === undefined) {
56124 cascaded = parentLayerObject['cascaded'];
56125 }
56126 layerObject['cascaded'] = cascaded;
56127
56128 var opaque = ol.format.XSD.readBooleanString(node.getAttribute('opaque'));
56129 if (opaque === undefined) {
56130 opaque = parentLayerObject['opaque'];
56131 }
56132 layerObject['opaque'] = opaque !== undefined ? opaque : false;
56133
56134 var noSubsets =
56135 ol.format.XSD.readBooleanString(node.getAttribute('noSubsets'));
56136 if (noSubsets === undefined) {
56137 noSubsets = parentLayerObject['noSubsets'];
56138 }
56139 layerObject['noSubsets'] = noSubsets !== undefined ? noSubsets : false;
56140
56141 var fixedWidth =
56142 ol.format.XSD.readDecimalString(node.getAttribute('fixedWidth'));
56143 if (!fixedWidth) {
56144 fixedWidth = parentLayerObject['fixedWidth'];
56145 }
56146 layerObject['fixedWidth'] = fixedWidth;
56147
56148 var fixedHeight =
56149 ol.format.XSD.readDecimalString(node.getAttribute('fixedHeight'));
56150 if (!fixedHeight) {
56151 fixedHeight = parentLayerObject['fixedHeight'];
56152 }
56153 layerObject['fixedHeight'] = fixedHeight;
56154
56155 // See 7.2.4.8
56156 var addKeys = ['Style', 'CRS', 'AuthorityURL'];
56157 addKeys.forEach(function(key) {
56158 if (key in parentLayerObject) {
56159 var childValue = layerObject[key] || [];
56160 layerObject[key] = childValue.concat(parentLayerObject[key]);
56161 }
56162 });
56163
56164 var replaceKeys = ['EX_GeographicBoundingBox', 'BoundingBox', 'Dimension',
56165 'Attribution', 'MinScaleDenominator', 'MaxScaleDenominator'];
56166 replaceKeys.forEach(function(key) {
56167 if (!(key in layerObject)) {
56168 var parentValue = parentLayerObject[key];
56169 layerObject[key] = parentValue;
56170 }
56171 });
56172
56173 return layerObject;
56174};
56175
56176
56177/**
56178 * @private
56179 * @param {Node} node Node.
56180 * @param {Array.<*>} objectStack Object stack.
56181 * @return {Object} Dimension object.
56182 */
56183ol.format.WMSCapabilities.readDimension_ = function(node, objectStack) {
56184 var dimensionObject = {
56185 'name': node.getAttribute('name'),
56186 'units': node.getAttribute('units'),
56187 'unitSymbol': node.getAttribute('unitSymbol'),
56188 'default': node.getAttribute('default'),
56189 'multipleValues': ol.format.XSD.readBooleanString(
56190 node.getAttribute('multipleValues')),
56191 'nearestValue': ol.format.XSD.readBooleanString(
56192 node.getAttribute('nearestValue')),
56193 'current': ol.format.XSD.readBooleanString(node.getAttribute('current')),
56194 'values': ol.format.XSD.readString(node)
56195 };
56196 return dimensionObject;
56197};
56198
56199
56200/**
56201 * @private
56202 * @param {Node} node Node.
56203 * @param {Array.<*>} objectStack Object stack.
56204 * @return {Object|undefined} Online resource object.
56205 */
56206ol.format.WMSCapabilities.readFormatOnlineresource_ = function(node, objectStack) {
56207 return ol.xml.pushParseAndPop(
56208 {}, ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_,
56209 node, objectStack);
56210};
56211
56212
56213/**
56214 * @private
56215 * @param {Node} node Node.
56216 * @param {Array.<*>} objectStack Object stack.
56217 * @return {Object|undefined} Request object.
56218 */
56219ol.format.WMSCapabilities.readRequest_ = function(node, objectStack) {
56220 return ol.xml.pushParseAndPop(
56221 {}, ol.format.WMSCapabilities.REQUEST_PARSERS_, node, objectStack);
56222};
56223
56224
56225/**
56226 * @private
56227 * @param {Node} node Node.
56228 * @param {Array.<*>} objectStack Object stack.
56229 * @return {Object|undefined} DCP type object.
56230 */
56231ol.format.WMSCapabilities.readDCPType_ = function(node, objectStack) {
56232 return ol.xml.pushParseAndPop(
56233 {}, ol.format.WMSCapabilities.DCPTYPE_PARSERS_, node, objectStack);
56234};
56235
56236
56237/**
56238 * @private
56239 * @param {Node} node Node.
56240 * @param {Array.<*>} objectStack Object stack.
56241 * @return {Object|undefined} HTTP object.
56242 */
56243ol.format.WMSCapabilities.readHTTP_ = function(node, objectStack) {
56244 return ol.xml.pushParseAndPop(
56245 {}, ol.format.WMSCapabilities.HTTP_PARSERS_, node, objectStack);
56246};
56247
56248
56249/**
56250 * @private
56251 * @param {Node} node Node.
56252 * @param {Array.<*>} objectStack Object stack.
56253 * @return {Object|undefined} Operation type object.
56254 */
56255ol.format.WMSCapabilities.readOperationType_ = function(node, objectStack) {
56256 return ol.xml.pushParseAndPop(
56257 {}, ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_, node, objectStack);
56258};
56259
56260
56261/**
56262 * @private
56263 * @param {Node} node Node.
56264 * @param {Array.<*>} objectStack Object stack.
56265 * @return {Object|undefined} Online resource object.
56266 */
56267ol.format.WMSCapabilities.readSizedFormatOnlineresource_ = function(node, objectStack) {
56268 var formatOnlineresource =
56269 ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
56270 if (formatOnlineresource) {
56271 var size = [
56272 ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('width')),
56273 ol.format.XSD.readNonNegativeIntegerString(node.getAttribute('height'))
56274 ];
56275 formatOnlineresource['size'] = size;
56276 return formatOnlineresource;
56277 }
56278 return undefined;
56279};
56280
56281
56282/**
56283 * @private
56284 * @param {Node} node Node.
56285 * @param {Array.<*>} objectStack Object stack.
56286 * @return {Object|undefined} Authority URL object.
56287 */
56288ol.format.WMSCapabilities.readAuthorityURL_ = function(node, objectStack) {
56289 var authorityObject =
56290 ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
56291 if (authorityObject) {
56292 authorityObject['name'] = node.getAttribute('name');
56293 return authorityObject;
56294 }
56295 return undefined;
56296};
56297
56298
56299/**
56300 * @private
56301 * @param {Node} node Node.
56302 * @param {Array.<*>} objectStack Object stack.
56303 * @return {Object|undefined} Metadata URL object.
56304 */
56305ol.format.WMSCapabilities.readMetadataURL_ = function(node, objectStack) {
56306 var metadataObject =
56307 ol.format.WMSCapabilities.readFormatOnlineresource_(node, objectStack);
56308 if (metadataObject) {
56309 metadataObject['type'] = node.getAttribute('type');
56310 return metadataObject;
56311 }
56312 return undefined;
56313};
56314
56315
56316/**
56317 * @private
56318 * @param {Node} node Node.
56319 * @param {Array.<*>} objectStack Object stack.
56320 * @return {Object|undefined} Style object.
56321 */
56322ol.format.WMSCapabilities.readStyle_ = function(node, objectStack) {
56323 return ol.xml.pushParseAndPop(
56324 {}, ol.format.WMSCapabilities.STYLE_PARSERS_, node, objectStack);
56325};
56326
56327
56328/**
56329 * @private
56330 * @param {Node} node Node.
56331 * @param {Array.<*>} objectStack Object stack.
56332 * @return {Array.<string>|undefined} Keyword list.
56333 */
56334ol.format.WMSCapabilities.readKeywordList_ = function(node, objectStack) {
56335 return ol.xml.pushParseAndPop(
56336 [], ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_, node, objectStack);
56337};
56338
56339
56340/**
56341 * @const
56342 * @private
56343 * @type {Array.<string>}
56344 */
56345ol.format.WMSCapabilities.NAMESPACE_URIS_ = [
56346 null,
56347 'http://www.opengis.net/wms'
56348];
56349
56350
56351/**
56352 * @const
56353 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56354 * @private
56355 */
56356ol.format.WMSCapabilities.PARSERS_ = ol.xml.makeStructureNS(
56357 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56358 'Service': ol.xml.makeObjectPropertySetter(
56359 ol.format.WMSCapabilities.readService_),
56360 'Capability': ol.xml.makeObjectPropertySetter(
56361 ol.format.WMSCapabilities.readCapability_)
56362 });
56363
56364
56365/**
56366 * @const
56367 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56368 * @private
56369 */
56370ol.format.WMSCapabilities.CAPABILITY_PARSERS_ = ol.xml.makeStructureNS(
56371 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56372 'Request': ol.xml.makeObjectPropertySetter(
56373 ol.format.WMSCapabilities.readRequest_),
56374 'Exception': ol.xml.makeObjectPropertySetter(
56375 ol.format.WMSCapabilities.readException_),
56376 'Layer': ol.xml.makeObjectPropertySetter(
56377 ol.format.WMSCapabilities.readCapabilityLayer_)
56378 });
56379
56380
56381/**
56382 * @const
56383 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56384 * @private
56385 */
56386ol.format.WMSCapabilities.SERVICE_PARSERS_ = ol.xml.makeStructureNS(
56387 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56388 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56389 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56390 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56391 'KeywordList': ol.xml.makeObjectPropertySetter(
56392 ol.format.WMSCapabilities.readKeywordList_),
56393 'OnlineResource': ol.xml.makeObjectPropertySetter(
56394 ol.format.XLink.readHref),
56395 'ContactInformation': ol.xml.makeObjectPropertySetter(
56396 ol.format.WMSCapabilities.readContactInformation_),
56397 'Fees': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56398 'AccessConstraints': ol.xml.makeObjectPropertySetter(
56399 ol.format.XSD.readString),
56400 'LayerLimit': ol.xml.makeObjectPropertySetter(
56401 ol.format.XSD.readNonNegativeInteger),
56402 'MaxWidth': ol.xml.makeObjectPropertySetter(
56403 ol.format.XSD.readNonNegativeInteger),
56404 'MaxHeight': ol.xml.makeObjectPropertySetter(
56405 ol.format.XSD.readNonNegativeInteger)
56406 });
56407
56408
56409/**
56410 * @const
56411 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56412 * @private
56413 */
56414ol.format.WMSCapabilities.CONTACT_INFORMATION_PARSERS_ = ol.xml.makeStructureNS(
56415 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56416 'ContactPersonPrimary': ol.xml.makeObjectPropertySetter(
56417 ol.format.WMSCapabilities.readContactPersonPrimary_),
56418 'ContactPosition': ol.xml.makeObjectPropertySetter(
56419 ol.format.XSD.readString),
56420 'ContactAddress': ol.xml.makeObjectPropertySetter(
56421 ol.format.WMSCapabilities.readContactAddress_),
56422 'ContactVoiceTelephone': ol.xml.makeObjectPropertySetter(
56423 ol.format.XSD.readString),
56424 'ContactFacsimileTelephone': ol.xml.makeObjectPropertySetter(
56425 ol.format.XSD.readString),
56426 'ContactElectronicMailAddress': ol.xml.makeObjectPropertySetter(
56427 ol.format.XSD.readString)
56428 });
56429
56430
56431/**
56432 * @const
56433 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56434 * @private
56435 */
56436ol.format.WMSCapabilities.CONTACT_PERSON_PARSERS_ = ol.xml.makeStructureNS(
56437 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56438 'ContactPerson': ol.xml.makeObjectPropertySetter(
56439 ol.format.XSD.readString),
56440 'ContactOrganization': ol.xml.makeObjectPropertySetter(
56441 ol.format.XSD.readString)
56442 });
56443
56444
56445/**
56446 * @const
56447 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56448 * @private
56449 */
56450ol.format.WMSCapabilities.CONTACT_ADDRESS_PARSERS_ = ol.xml.makeStructureNS(
56451 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56452 'AddressType': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56453 'Address': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56454 'City': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56455 'StateOrProvince': ol.xml.makeObjectPropertySetter(
56456 ol.format.XSD.readString),
56457 'PostCode': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56458 'Country': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString)
56459 });
56460
56461
56462/**
56463 * @const
56464 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56465 * @private
56466 */
56467ol.format.WMSCapabilities.EXCEPTION_PARSERS_ = ol.xml.makeStructureNS(
56468 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56469 'Format': ol.xml.makeArrayPusher(ol.format.XSD.readString)
56470 });
56471
56472
56473/**
56474 * @const
56475 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56476 * @private
56477 */
56478ol.format.WMSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(
56479 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56480 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56481 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56482 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56483 'KeywordList': ol.xml.makeObjectPropertySetter(
56484 ol.format.WMSCapabilities.readKeywordList_),
56485 'CRS': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
56486 'EX_GeographicBoundingBox': ol.xml.makeObjectPropertySetter(
56487 ol.format.WMSCapabilities.readEXGeographicBoundingBox_),
56488 'BoundingBox': ol.xml.makeObjectPropertyPusher(
56489 ol.format.WMSCapabilities.readBoundingBox_),
56490 'Dimension': ol.xml.makeObjectPropertyPusher(
56491 ol.format.WMSCapabilities.readDimension_),
56492 'Attribution': ol.xml.makeObjectPropertySetter(
56493 ol.format.WMSCapabilities.readAttribution_),
56494 'AuthorityURL': ol.xml.makeObjectPropertyPusher(
56495 ol.format.WMSCapabilities.readAuthorityURL_),
56496 'Identifier': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
56497 'MetadataURL': ol.xml.makeObjectPropertyPusher(
56498 ol.format.WMSCapabilities.readMetadataURL_),
56499 'DataURL': ol.xml.makeObjectPropertyPusher(
56500 ol.format.WMSCapabilities.readFormatOnlineresource_),
56501 'FeatureListURL': ol.xml.makeObjectPropertyPusher(
56502 ol.format.WMSCapabilities.readFormatOnlineresource_),
56503 'Style': ol.xml.makeObjectPropertyPusher(
56504 ol.format.WMSCapabilities.readStyle_),
56505 'MinScaleDenominator': ol.xml.makeObjectPropertySetter(
56506 ol.format.XSD.readDecimal),
56507 'MaxScaleDenominator': ol.xml.makeObjectPropertySetter(
56508 ol.format.XSD.readDecimal),
56509 'Layer': ol.xml.makeObjectPropertyPusher(
56510 ol.format.WMSCapabilities.readLayer_)
56511 });
56512
56513
56514/**
56515 * @const
56516 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56517 * @private
56518 */
56519ol.format.WMSCapabilities.ATTRIBUTION_PARSERS_ = ol.xml.makeStructureNS(
56520 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56521 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56522 'OnlineResource': ol.xml.makeObjectPropertySetter(
56523 ol.format.XLink.readHref),
56524 'LogoURL': ol.xml.makeObjectPropertySetter(
56525 ol.format.WMSCapabilities.readSizedFormatOnlineresource_)
56526 });
56527
56528
56529/**
56530 * @const
56531 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56532 * @private
56533 */
56534ol.format.WMSCapabilities.EX_GEOGRAPHIC_BOUNDING_BOX_PARSERS_ =
56535 ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56536 'westBoundLongitude': ol.xml.makeObjectPropertySetter(
56537 ol.format.XSD.readDecimal),
56538 'eastBoundLongitude': ol.xml.makeObjectPropertySetter(
56539 ol.format.XSD.readDecimal),
56540 'southBoundLatitude': ol.xml.makeObjectPropertySetter(
56541 ol.format.XSD.readDecimal),
56542 'northBoundLatitude': ol.xml.makeObjectPropertySetter(
56543 ol.format.XSD.readDecimal)
56544 });
56545
56546
56547/**
56548 * @const
56549 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56550 * @private
56551 */
56552ol.format.WMSCapabilities.REQUEST_PARSERS_ = ol.xml.makeStructureNS(
56553 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56554 'GetCapabilities': ol.xml.makeObjectPropertySetter(
56555 ol.format.WMSCapabilities.readOperationType_),
56556 'GetMap': ol.xml.makeObjectPropertySetter(
56557 ol.format.WMSCapabilities.readOperationType_),
56558 'GetFeatureInfo': ol.xml.makeObjectPropertySetter(
56559 ol.format.WMSCapabilities.readOperationType_)
56560 });
56561
56562
56563/**
56564 * @const
56565 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56566 * @private
56567 */
56568ol.format.WMSCapabilities.OPERATIONTYPE_PARSERS_ = ol.xml.makeStructureNS(
56569 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56570 'Format': ol.xml.makeObjectPropertyPusher(ol.format.XSD.readString),
56571 'DCPType': ol.xml.makeObjectPropertyPusher(
56572 ol.format.WMSCapabilities.readDCPType_)
56573 });
56574
56575
56576/**
56577 * @const
56578 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56579 * @private
56580 */
56581ol.format.WMSCapabilities.DCPTYPE_PARSERS_ = ol.xml.makeStructureNS(
56582 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56583 'HTTP': ol.xml.makeObjectPropertySetter(
56584 ol.format.WMSCapabilities.readHTTP_)
56585 });
56586
56587
56588/**
56589 * @const
56590 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56591 * @private
56592 */
56593ol.format.WMSCapabilities.HTTP_PARSERS_ = ol.xml.makeStructureNS(
56594 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56595 'Get': ol.xml.makeObjectPropertySetter(
56596 ol.format.WMSCapabilities.readFormatOnlineresource_),
56597 'Post': ol.xml.makeObjectPropertySetter(
56598 ol.format.WMSCapabilities.readFormatOnlineresource_)
56599 });
56600
56601
56602/**
56603 * @const
56604 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56605 * @private
56606 */
56607ol.format.WMSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(
56608 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56609 'Name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56610 'Title': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56611 'Abstract': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56612 'LegendURL': ol.xml.makeObjectPropertyPusher(
56613 ol.format.WMSCapabilities.readSizedFormatOnlineresource_),
56614 'StyleSheetURL': ol.xml.makeObjectPropertySetter(
56615 ol.format.WMSCapabilities.readFormatOnlineresource_),
56616 'StyleURL': ol.xml.makeObjectPropertySetter(
56617 ol.format.WMSCapabilities.readFormatOnlineresource_)
56618 });
56619
56620
56621/**
56622 * @const
56623 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56624 * @private
56625 */
56626ol.format.WMSCapabilities.FORMAT_ONLINERESOURCE_PARSERS_ =
56627 ol.xml.makeStructureNS(ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56628 'Format': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString),
56629 'OnlineResource': ol.xml.makeObjectPropertySetter(
56630 ol.format.XLink.readHref)
56631 });
56632
56633
56634/**
56635 * @const
56636 * @type {Object.<string, Object.<string, ol.XmlParser>>}
56637 * @private
56638 */
56639ol.format.WMSCapabilities.KEYWORDLIST_PARSERS_ = ol.xml.makeStructureNS(
56640 ol.format.WMSCapabilities.NAMESPACE_URIS_, {
56641 'Keyword': ol.xml.makeArrayPusher(ol.format.XSD.readString)
56642 });
56643
56644goog.provide('ol.format.WMSGetFeatureInfo');
56645
56646goog.require('ol');
56647goog.require('ol.array');
56648goog.require('ol.format.GML2');
56649goog.require('ol.format.XMLFeature');
56650goog.require('ol.obj');
56651goog.require('ol.xml');
56652
56653
56654/**
56655 * @classdesc
56656 * Format for reading WMSGetFeatureInfo format. It uses
56657 * {@link ol.format.GML2} to read features.
56658 *
56659 * @constructor
56660 * @extends {ol.format.XMLFeature}
56661 * @param {olx.format.WMSGetFeatureInfoOptions=} opt_options Options.
56662 * @api
56663 */
56664ol.format.WMSGetFeatureInfo = function(opt_options) {
56665
56666 var options = opt_options ? opt_options : {};
56667
56668 /**
56669 * @private
56670 * @type {string}
56671 */
56672 this.featureNS_ = 'http://mapserver.gis.umn.edu/mapserver';
56673
56674
56675 /**
56676 * @private
56677 * @type {ol.format.GML2}
56678 */
56679 this.gmlFormat_ = new ol.format.GML2();
56680
56681
56682 /**
56683 * @private
56684 * @type {Array.<string>}
56685 */
56686 this.layers_ = options.layers ? options.layers : null;
56687
56688 ol.format.XMLFeature.call(this);
56689};
56690ol.inherits(ol.format.WMSGetFeatureInfo, ol.format.XMLFeature);
56691
56692
56693/**
56694 * @const
56695 * @type {string}
56696 * @private
56697 */
56698ol.format.WMSGetFeatureInfo.featureIdentifier_ = '_feature';
56699
56700
56701/**
56702 * @const
56703 * @type {string}
56704 * @private
56705 */
56706ol.format.WMSGetFeatureInfo.layerIdentifier_ = '_layer';
56707
56708
56709/**
56710 * @param {Node} node Node.
56711 * @param {Array.<*>} objectStack Object stack.
56712 * @return {Array.<ol.Feature>} Features.
56713 * @private
56714 */
56715ol.format.WMSGetFeatureInfo.prototype.readFeatures_ = function(node, objectStack) {
56716 node.setAttribute('namespaceURI', this.featureNS_);
56717 var localName = node.localName;
56718 /** @type {Array.<ol.Feature>} */
56719 var features = [];
56720 if (node.childNodes.length === 0) {
56721 return features;
56722 }
56723 if (localName == 'msGMLOutput') {
56724 for (var i = 0, ii = node.childNodes.length; i < ii; i++) {
56725 var layer = node.childNodes[i];
56726 if (layer.nodeType !== Node.ELEMENT_NODE) {
56727 continue;
56728 }
56729 var context = objectStack[0];
56730
56731 var toRemove = ol.format.WMSGetFeatureInfo.layerIdentifier_;
56732 var layerName = layer.localName.replace(toRemove, '');
56733
56734 if (this.layers_ && !ol.array.includes(this.layers_, layerName)) {
56735 continue;
56736 }
56737
56738 var featureType = layerName +
56739 ol.format.WMSGetFeatureInfo.featureIdentifier_;
56740
56741 context['featureType'] = featureType;
56742 context['featureNS'] = this.featureNS_;
56743
56744 var parsers = {};
56745 parsers[featureType] = ol.xml.makeArrayPusher(
56746 this.gmlFormat_.readFeatureElement, this.gmlFormat_);
56747 var parsersNS = ol.xml.makeStructureNS(
56748 [context['featureNS'], null], parsers);
56749 layer.setAttribute('namespaceURI', this.featureNS_);
56750 var layerFeatures = ol.xml.pushParseAndPop(
56751 [], parsersNS, layer, objectStack, this.gmlFormat_);
56752 if (layerFeatures) {
56753 ol.array.extend(features, layerFeatures);
56754 }
56755 }
56756 }
56757 if (localName == 'FeatureCollection') {
56758 var gmlFeatures = ol.xml.pushParseAndPop([],
56759 this.gmlFormat_.FEATURE_COLLECTION_PARSERS, node,
56760 [{}], this.gmlFormat_);
56761 if (gmlFeatures) {
56762 features = gmlFeatures;
56763 }
56764 }
56765 return features;
56766};
56767
56768
56769/**
56770 * Read all features from a WMSGetFeatureInfo response.
56771 *
56772 * @function
56773 * @param {Document|Node|Object|string} source Source.
56774 * @param {olx.format.ReadOptions=} opt_options Options.
56775 * @return {Array.<ol.Feature>} Features.
56776 * @api
56777 */
56778ol.format.WMSGetFeatureInfo.prototype.readFeatures;
56779
56780
56781/**
56782 * @inheritDoc
56783 */
56784ol.format.WMSGetFeatureInfo.prototype.readFeaturesFromNode = function(node, opt_options) {
56785 var options = {};
56786 if (opt_options) {
56787 ol.obj.assign(options, this.getReadOptions(node, opt_options));
56788 }
56789 return this.readFeatures_(node, [options]);
56790};
56791
56792
56793/**
56794 * Not implemented.
56795 * @inheritDoc
56796 */
56797ol.format.WMSGetFeatureInfo.prototype.writeFeatureNode = function(feature, opt_options) {};
56798
56799
56800/**
56801 * Not implemented.
56802 * @inheritDoc
56803 */
56804ol.format.WMSGetFeatureInfo.prototype.writeFeaturesNode = function(features, opt_options) {};
56805
56806
56807/**
56808 * Not implemented.
56809 * @inheritDoc
56810 */
56811ol.format.WMSGetFeatureInfo.prototype.writeGeometryNode = function(geometry, opt_options) {};
56812
56813goog.provide('ol.format.WMTSCapabilities');
56814
56815goog.require('ol');
56816goog.require('ol.extent');
56817goog.require('ol.format.OWS');
56818goog.require('ol.format.XLink');
56819goog.require('ol.format.XML');
56820goog.require('ol.format.XSD');
56821goog.require('ol.xml');
56822
56823
56824/**
56825 * @classdesc
56826 * Format for reading WMTS capabilities data.
56827 *
56828 * @constructor
56829 * @extends {ol.format.XML}
56830 * @api
56831 */
56832ol.format.WMTSCapabilities = function() {
56833 ol.format.XML.call(this);
56834
56835 /**
56836 * @type {ol.format.OWS}
56837 * @private
56838 */
56839 this.owsParser_ = new ol.format.OWS();
56840};
56841ol.inherits(ol.format.WMTSCapabilities, ol.format.XML);
56842
56843
56844/**
56845 * Read a WMTS capabilities document.
56846 *
56847 * @function
56848 * @param {Document|Node|string} source The XML source.
56849 * @return {Object} An object representing the WMTS capabilities.
56850 * @api
56851 */
56852ol.format.WMTSCapabilities.prototype.read;
56853
56854
56855/**
56856 * @inheritDoc
56857 */
56858ol.format.WMTSCapabilities.prototype.readFromDocument = function(doc) {
56859 for (var n = doc.firstChild; n; n = n.nextSibling) {
56860 if (n.nodeType == Node.ELEMENT_NODE) {
56861 return this.readFromNode(n);
56862 }
56863 }
56864 return null;
56865};
56866
56867
56868/**
56869 * @inheritDoc
56870 */
56871ol.format.WMTSCapabilities.prototype.readFromNode = function(node) {
56872 var version = node.getAttribute('version').trim();
56873 var WMTSCapabilityObject = this.owsParser_.readFromNode(node);
56874 if (!WMTSCapabilityObject) {
56875 return null;
56876 }
56877 WMTSCapabilityObject['version'] = version;
56878 WMTSCapabilityObject = ol.xml.pushParseAndPop(WMTSCapabilityObject,
56879 ol.format.WMTSCapabilities.PARSERS_, node, []);
56880 return WMTSCapabilityObject ? WMTSCapabilityObject : null;
56881};
56882
56883
56884/**
56885 * @private
56886 * @param {Node} node Node.
56887 * @param {Array.<*>} objectStack Object stack.
56888 * @return {Object|undefined} Attribution object.
56889 */
56890ol.format.WMTSCapabilities.readContents_ = function(node, objectStack) {
56891 return ol.xml.pushParseAndPop({},
56892 ol.format.WMTSCapabilities.CONTENTS_PARSERS_, node, objectStack);
56893};
56894
56895
56896/**
56897 * @private
56898 * @param {Node} node Node.
56899 * @param {Array.<*>} objectStack Object stack.
56900 * @return {Object|undefined} Layers object.
56901 */
56902ol.format.WMTSCapabilities.readLayer_ = function(node, objectStack) {
56903 return ol.xml.pushParseAndPop({},
56904 ol.format.WMTSCapabilities.LAYER_PARSERS_, node, objectStack);
56905};
56906
56907
56908/**
56909 * @private
56910 * @param {Node} node Node.
56911 * @param {Array.<*>} objectStack Object stack.
56912 * @return {Object|undefined} Tile Matrix Set object.
56913 */
56914ol.format.WMTSCapabilities.readTileMatrixSet_ = function(node, objectStack) {
56915 return ol.xml.pushParseAndPop({},
56916 ol.format.WMTSCapabilities.TMS_PARSERS_, node, objectStack);
56917};
56918
56919
56920/**
56921 * @private
56922 * @param {Node} node Node.
56923 * @param {Array.<*>} objectStack Object stack.
56924 * @return {Object|undefined} Style object.
56925 */
56926ol.format.WMTSCapabilities.readStyle_ = function(node, objectStack) {
56927 var style = ol.xml.pushParseAndPop({},
56928 ol.format.WMTSCapabilities.STYLE_PARSERS_, node, objectStack);
56929 if (!style) {
56930 return undefined;
56931 }
56932 var isDefault = node.getAttribute('isDefault') === 'true';
56933 style['isDefault'] = isDefault;
56934 return style;
56935
56936};
56937
56938
56939/**
56940 * @private
56941 * @param {Node} node Node.
56942 * @param {Array.<*>} objectStack Object stack.
56943 * @return {Object|undefined} Tile Matrix Set Link object.
56944 */
56945ol.format.WMTSCapabilities.readTileMatrixSetLink_ = function(node,
56946 objectStack) {
56947 return ol.xml.pushParseAndPop({},
56948 ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_, node, objectStack);
56949};
56950
56951
56952/**
56953 * @private
56954 * @param {Node} node Node.
56955 * @param {Array.<*>} objectStack Object stack.
56956 * @return {Object|undefined} Dimension object.
56957 */
56958ol.format.WMTSCapabilities.readDimensions_ = function(node, objectStack) {
56959 return ol.xml.pushParseAndPop({},
56960 ol.format.WMTSCapabilities.DIMENSION_PARSERS_, node, objectStack);
56961};
56962
56963
56964/**
56965 * @private
56966 * @param {Node} node Node.
56967 * @param {Array.<*>} objectStack Object stack.
56968 * @return {Object|undefined} Resource URL object.
56969 */
56970ol.format.WMTSCapabilities.readResourceUrl_ = function(node, objectStack) {
56971 var format = node.getAttribute('format');
56972 var template = node.getAttribute('template');
56973 var resourceType = node.getAttribute('resourceType');
56974 var resource = {};
56975 if (format) {
56976 resource['format'] = format;
56977 }
56978 if (template) {
56979 resource['template'] = template;
56980 }
56981 if (resourceType) {
56982 resource['resourceType'] = resourceType;
56983 }
56984 return resource;
56985};
56986
56987
56988/**
56989 * @private
56990 * @param {Node} node Node.
56991 * @param {Array.<*>} objectStack Object stack.
56992 * @return {Object|undefined} WGS84 BBox object.
56993 */
56994ol.format.WMTSCapabilities.readWgs84BoundingBox_ = function(node, objectStack) {
56995 var coordinates = ol.xml.pushParseAndPop([],
56996 ol.format.WMTSCapabilities.WGS84_BBOX_READERS_, node, objectStack);
56997 if (coordinates.length != 2) {
56998 return undefined;
56999 }
57000 return ol.extent.boundingExtent(coordinates);
57001};
57002
57003
57004/**
57005 * @private
57006 * @param {Node} node Node.
57007 * @param {Array.<*>} objectStack Object stack.
57008 * @return {Object|undefined} Legend object.
57009 */
57010ol.format.WMTSCapabilities.readLegendUrl_ = function(node, objectStack) {
57011 var legend = {};
57012 legend['format'] = node.getAttribute('format');
57013 legend['href'] = ol.format.XLink.readHref(node);
57014 return legend;
57015};
57016
57017
57018/**
57019 * @private
57020 * @param {Node} node Node.
57021 * @param {Array.<*>} objectStack Object stack.
57022 * @return {Object|undefined} Coordinates object.
57023 */
57024ol.format.WMTSCapabilities.readCoordinates_ = function(node, objectStack) {
57025 var coordinates = ol.format.XSD.readString(node).split(' ');
57026 if (!coordinates || coordinates.length != 2) {
57027 return undefined;
57028 }
57029 var x = +coordinates[0];
57030 var y = +coordinates[1];
57031 if (isNaN(x) || isNaN(y)) {
57032 return undefined;
57033 }
57034 return [x, y];
57035};
57036
57037
57038/**
57039 * @private
57040 * @param {Node} node Node.
57041 * @param {Array.<*>} objectStack Object stack.
57042 * @return {Object|undefined} TileMatrix object.
57043 */
57044ol.format.WMTSCapabilities.readTileMatrix_ = function(node, objectStack) {
57045 return ol.xml.pushParseAndPop({},
57046 ol.format.WMTSCapabilities.TM_PARSERS_, node, objectStack);
57047};
57048
57049
57050/**
57051 * @private
57052 * @param {Node} node Node.
57053 * @param {Array.<*>} objectStack Object stack.
57054 * @return {Object|undefined} TileMatrixSetLimits Object.
57055 */
57056ol.format.WMTSCapabilities.readTileMatrixLimitsList_ = function(node,
57057 objectStack) {
57058 return ol.xml.pushParseAndPop([],
57059 ol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_, node,
57060 objectStack);
57061};
57062
57063
57064/**
57065 * @private
57066 * @param {Node} node Node.
57067 * @param {Array.<*>} objectStack Object stack.
57068 * @return {Object|undefined} TileMatrixLimits Array.
57069 */
57070ol.format.WMTSCapabilities.readTileMatrixLimits_ = function(node, objectStack) {
57071 return ol.xml.pushParseAndPop({},
57072 ol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_, node, objectStack);
57073};
57074
57075
57076/**
57077 * @const
57078 * @private
57079 * @type {Array.<string>}
57080 */
57081ol.format.WMTSCapabilities.NAMESPACE_URIS_ = [
57082 null,
57083 'http://www.opengis.net/wmts/1.0'
57084];
57085
57086
57087/**
57088 * @const
57089 * @private
57090 * @type {Array.<string>}
57091 */
57092ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_ = [
57093 null,
57094 'http://www.opengis.net/ows/1.1'
57095];
57096
57097
57098/**
57099 * @const
57100 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57101 * @private
57102 */
57103ol.format.WMTSCapabilities.PARSERS_ = ol.xml.makeStructureNS(
57104 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57105 'Contents': ol.xml.makeObjectPropertySetter(
57106 ol.format.WMTSCapabilities.readContents_)
57107 });
57108
57109
57110/**
57111 * @const
57112 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57113 * @private
57114 */
57115ol.format.WMTSCapabilities.CONTENTS_PARSERS_ = ol.xml.makeStructureNS(
57116 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57117 'Layer': ol.xml.makeObjectPropertyPusher(
57118 ol.format.WMTSCapabilities.readLayer_),
57119 'TileMatrixSet': ol.xml.makeObjectPropertyPusher(
57120 ol.format.WMTSCapabilities.readTileMatrixSet_)
57121 });
57122
57123
57124/**
57125 * @const
57126 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57127 * @private
57128 */
57129ol.format.WMTSCapabilities.LAYER_PARSERS_ = ol.xml.makeStructureNS(
57130 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57131 'Style': ol.xml.makeObjectPropertyPusher(
57132 ol.format.WMTSCapabilities.readStyle_),
57133 'Format': ol.xml.makeObjectPropertyPusher(
57134 ol.format.XSD.readString),
57135 'TileMatrixSetLink': ol.xml.makeObjectPropertyPusher(
57136 ol.format.WMTSCapabilities.readTileMatrixSetLink_),
57137 'Dimension': ol.xml.makeObjectPropertyPusher(
57138 ol.format.WMTSCapabilities.readDimensions_),
57139 'ResourceURL': ol.xml.makeObjectPropertyPusher(
57140 ol.format.WMTSCapabilities.readResourceUrl_)
57141 }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57142 'Title': ol.xml.makeObjectPropertySetter(
57143 ol.format.XSD.readString),
57144 'Abstract': ol.xml.makeObjectPropertySetter(
57145 ol.format.XSD.readString),
57146 'WGS84BoundingBox': ol.xml.makeObjectPropertySetter(
57147 ol.format.WMTSCapabilities.readWgs84BoundingBox_),
57148 'Identifier': ol.xml.makeObjectPropertySetter(
57149 ol.format.XSD.readString)
57150 }));
57151
57152
57153/**
57154 * @const
57155 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57156 * @private
57157 */
57158ol.format.WMTSCapabilities.STYLE_PARSERS_ = ol.xml.makeStructureNS(
57159 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57160 'LegendURL': ol.xml.makeObjectPropertyPusher(
57161 ol.format.WMTSCapabilities.readLegendUrl_)
57162 }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57163 'Title': ol.xml.makeObjectPropertySetter(
57164 ol.format.XSD.readString),
57165 'Identifier': ol.xml.makeObjectPropertySetter(
57166 ol.format.XSD.readString)
57167 }));
57168
57169
57170/**
57171 * @const
57172 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57173 * @private
57174 */
57175ol.format.WMTSCapabilities.TMS_LINKS_PARSERS_ = ol.xml.makeStructureNS(
57176 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57177 'TileMatrixSet': ol.xml.makeObjectPropertySetter(
57178 ol.format.XSD.readString),
57179 'TileMatrixSetLimits': ol.xml.makeObjectPropertySetter(
57180 ol.format.WMTSCapabilities.readTileMatrixLimitsList_)
57181 });
57182
57183/**
57184 * @const
57185 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57186 * @private
57187 */
57188ol.format.WMTSCapabilities.TMS_LIMITS_LIST_PARSERS_ = ol.xml.makeStructureNS(
57189 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57190 'TileMatrixLimits': ol.xml.makeArrayPusher(
57191 ol.format.WMTSCapabilities.readTileMatrixLimits_)
57192 });
57193
57194
57195/**
57196 * @const
57197 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57198 * @private
57199 */
57200ol.format.WMTSCapabilities.TMS_LIMITS_PARSERS_ = ol.xml.makeStructureNS(
57201 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57202 'TileMatrix': ol.xml.makeObjectPropertySetter(
57203 ol.format.XSD.readString),
57204 'MinTileRow': ol.xml.makeObjectPropertySetter(
57205 ol.format.XSD.readNonNegativeInteger),
57206 'MaxTileRow': ol.xml.makeObjectPropertySetter(
57207 ol.format.XSD.readNonNegativeInteger),
57208 'MinTileCol': ol.xml.makeObjectPropertySetter(
57209 ol.format.XSD.readNonNegativeInteger),
57210 'MaxTileCol': ol.xml.makeObjectPropertySetter(
57211 ol.format.XSD.readNonNegativeInteger)
57212 });
57213
57214
57215/**
57216 * @const
57217 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57218 * @private
57219 */
57220ol.format.WMTSCapabilities.DIMENSION_PARSERS_ = ol.xml.makeStructureNS(
57221 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57222 'Default': ol.xml.makeObjectPropertySetter(
57223 ol.format.XSD.readString),
57224 'Value': ol.xml.makeObjectPropertyPusher(
57225 ol.format.XSD.readString)
57226 }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57227 'Identifier': ol.xml.makeObjectPropertySetter(
57228 ol.format.XSD.readString)
57229 }));
57230
57231
57232/**
57233 * @const
57234 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57235 * @private
57236 */
57237ol.format.WMTSCapabilities.WGS84_BBOX_READERS_ = ol.xml.makeStructureNS(
57238 ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57239 'LowerCorner': ol.xml.makeArrayPusher(
57240 ol.format.WMTSCapabilities.readCoordinates_),
57241 'UpperCorner': ol.xml.makeArrayPusher(
57242 ol.format.WMTSCapabilities.readCoordinates_)
57243 });
57244
57245
57246/**
57247 * @const
57248 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57249 * @private
57250 */
57251ol.format.WMTSCapabilities.TMS_PARSERS_ = ol.xml.makeStructureNS(
57252 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57253 'WellKnownScaleSet': ol.xml.makeObjectPropertySetter(
57254 ol.format.XSD.readString),
57255 'TileMatrix': ol.xml.makeObjectPropertyPusher(
57256 ol.format.WMTSCapabilities.readTileMatrix_)
57257 }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57258 'SupportedCRS': ol.xml.makeObjectPropertySetter(
57259 ol.format.XSD.readString),
57260 'Identifier': ol.xml.makeObjectPropertySetter(
57261 ol.format.XSD.readString)
57262 }));
57263
57264
57265/**
57266 * @const
57267 * @type {Object.<string, Object.<string, ol.XmlParser>>}
57268 * @private
57269 */
57270ol.format.WMTSCapabilities.TM_PARSERS_ = ol.xml.makeStructureNS(
57271 ol.format.WMTSCapabilities.NAMESPACE_URIS_, {
57272 'TopLeftCorner': ol.xml.makeObjectPropertySetter(
57273 ol.format.WMTSCapabilities.readCoordinates_),
57274 'ScaleDenominator': ol.xml.makeObjectPropertySetter(
57275 ol.format.XSD.readDecimal),
57276 'TileWidth': ol.xml.makeObjectPropertySetter(
57277 ol.format.XSD.readNonNegativeInteger),
57278 'TileHeight': ol.xml.makeObjectPropertySetter(
57279 ol.format.XSD.readNonNegativeInteger),
57280 'MatrixWidth': ol.xml.makeObjectPropertySetter(
57281 ol.format.XSD.readNonNegativeInteger),
57282 'MatrixHeight': ol.xml.makeObjectPropertySetter(
57283 ol.format.XSD.readNonNegativeInteger)
57284 }, ol.xml.makeStructureNS(ol.format.WMTSCapabilities.OWS_NAMESPACE_URIS_, {
57285 'Identifier': ol.xml.makeObjectPropertySetter(
57286 ol.format.XSD.readString)
57287 }));
57288
57289goog.provide('ol.GeolocationProperty');
57290
57291
57292/**
57293 * @enum {string}
57294 */
57295ol.GeolocationProperty = {
57296 ACCURACY: 'accuracy',
57297 ACCURACY_GEOMETRY: 'accuracyGeometry',
57298 ALTITUDE: 'altitude',
57299 ALTITUDE_ACCURACY: 'altitudeAccuracy',
57300 HEADING: 'heading',
57301 POSITION: 'position',
57302 PROJECTION: 'projection',
57303 SPEED: 'speed',
57304 TRACKING: 'tracking',
57305 TRACKING_OPTIONS: 'trackingOptions'
57306};
57307
57308// FIXME handle geolocation not supported
57309
57310goog.provide('ol.Geolocation');
57311
57312goog.require('ol');
57313goog.require('ol.GeolocationProperty');
57314goog.require('ol.Object');
57315goog.require('ol.Sphere');
57316goog.require('ol.events');
57317goog.require('ol.events.EventType');
57318goog.require('ol.geom.Polygon');
57319goog.require('ol.has');
57320goog.require('ol.math');
57321goog.require('ol.proj');
57322goog.require('ol.proj.EPSG4326');
57323
57324
57325/**
57326 * @classdesc
57327 * Helper class for providing HTML5 Geolocation capabilities.
57328 * The [Geolocation API](http://www.w3.org/TR/geolocation-API/)
57329 * is used to locate a user's position.
57330 *
57331 * To get notified of position changes, register a listener for the generic
57332 * `change` event on your instance of `ol.Geolocation`.
57333 *
57334 * Example:
57335 *
57336 * var geolocation = new ol.Geolocation({
57337 * // take the projection to use from the map's view
57338 * projection: view.getProjection()
57339 * });
57340 * // listen to changes in position
57341 * geolocation.on('change', function(evt) {
57342 * window.console.log(geolocation.getPosition());
57343 * });
57344 *
57345 * @fires error
57346 * @constructor
57347 * @extends {ol.Object}
57348 * @param {olx.GeolocationOptions=} opt_options Options.
57349 * @api
57350 */
57351ol.Geolocation = function(opt_options) {
57352
57353 ol.Object.call(this);
57354
57355 var options = opt_options || {};
57356
57357 /**
57358 * The unprojected (EPSG:4326) device position.
57359 * @private
57360 * @type {ol.Coordinate}
57361 */
57362 this.position_ = null;
57363
57364 /**
57365 * @private
57366 * @type {ol.TransformFunction}
57367 */
57368 this.transform_ = ol.proj.identityTransform;
57369
57370 /**
57371 * @private
57372 * @type {ol.Sphere}
57373 */
57374 this.sphere_ = new ol.Sphere(ol.proj.EPSG4326.RADIUS);
57375
57376 /**
57377 * @private
57378 * @type {number|undefined}
57379 */
57380 this.watchId_ = undefined;
57381
57382 ol.events.listen(
57383 this, ol.Object.getChangeEventType(ol.GeolocationProperty.PROJECTION),
57384 this.handleProjectionChanged_, this);
57385 ol.events.listen(
57386 this, ol.Object.getChangeEventType(ol.GeolocationProperty.TRACKING),
57387 this.handleTrackingChanged_, this);
57388
57389 if (options.projection !== undefined) {
57390 this.setProjection(options.projection);
57391 }
57392 if (options.trackingOptions !== undefined) {
57393 this.setTrackingOptions(options.trackingOptions);
57394 }
57395
57396 this.setTracking(options.tracking !== undefined ? options.tracking : false);
57397
57398};
57399ol.inherits(ol.Geolocation, ol.Object);
57400
57401
57402/**
57403 * @inheritDoc
57404 */
57405ol.Geolocation.prototype.disposeInternal = function() {
57406 this.setTracking(false);
57407 ol.Object.prototype.disposeInternal.call(this);
57408};
57409
57410
57411/**
57412 * @private
57413 */
57414ol.Geolocation.prototype.handleProjectionChanged_ = function() {
57415 var projection = this.getProjection();
57416 if (projection) {
57417 this.transform_ = ol.proj.getTransformFromProjections(
57418 ol.proj.get('EPSG:4326'), projection);
57419 if (this.position_) {
57420 this.set(
57421 ol.GeolocationProperty.POSITION, this.transform_(this.position_));
57422 }
57423 }
57424};
57425
57426
57427/**
57428 * @private
57429 */
57430ol.Geolocation.prototype.handleTrackingChanged_ = function() {
57431 if (ol.has.GEOLOCATION) {
57432 var tracking = this.getTracking();
57433 if (tracking && this.watchId_ === undefined) {
57434 this.watchId_ = navigator.geolocation.watchPosition(
57435 this.positionChange_.bind(this),
57436 this.positionError_.bind(this),
57437 this.getTrackingOptions());
57438 } else if (!tracking && this.watchId_ !== undefined) {
57439 navigator.geolocation.clearWatch(this.watchId_);
57440 this.watchId_ = undefined;
57441 }
57442 }
57443};
57444
57445
57446/**
57447 * @private
57448 * @param {GeolocationPosition} position position event.
57449 */
57450ol.Geolocation.prototype.positionChange_ = function(position) {
57451 var coords = position.coords;
57452 this.set(ol.GeolocationProperty.ACCURACY, coords.accuracy);
57453 this.set(ol.GeolocationProperty.ALTITUDE,
57454 coords.altitude === null ? undefined : coords.altitude);
57455 this.set(ol.GeolocationProperty.ALTITUDE_ACCURACY,
57456 coords.altitudeAccuracy === null ?
57457 undefined : coords.altitudeAccuracy);
57458 this.set(ol.GeolocationProperty.HEADING, coords.heading === null ?
57459 undefined : ol.math.toRadians(coords.heading));
57460 if (!this.position_) {
57461 this.position_ = [coords.longitude, coords.latitude];
57462 } else {
57463 this.position_[0] = coords.longitude;
57464 this.position_[1] = coords.latitude;
57465 }
57466 var projectedPosition = this.transform_(this.position_);
57467 this.set(ol.GeolocationProperty.POSITION, projectedPosition);
57468 this.set(ol.GeolocationProperty.SPEED,
57469 coords.speed === null ? undefined : coords.speed);
57470 var geometry = ol.geom.Polygon.circular(
57471 this.sphere_, this.position_, coords.accuracy);
57472 geometry.applyTransform(this.transform_);
57473 this.set(ol.GeolocationProperty.ACCURACY_GEOMETRY, geometry);
57474 this.changed();
57475};
57476
57477/**
57478 * Triggered when the Geolocation returns an error.
57479 * @event error
57480 * @api
57481 */
57482
57483/**
57484 * @private
57485 * @param {GeolocationPositionError} error error object.
57486 */
57487ol.Geolocation.prototype.positionError_ = function(error) {
57488 error.type = ol.events.EventType.ERROR;
57489 this.setTracking(false);
57490 this.dispatchEvent(/** @type {{type: string, target: undefined}} */ (error));
57491};
57492
57493
57494/**
57495 * Get the accuracy of the position in meters.
57496 * @return {number|undefined} The accuracy of the position measurement in
57497 * meters.
57498 * @observable
57499 * @api
57500 */
57501ol.Geolocation.prototype.getAccuracy = function() {
57502 return /** @type {number|undefined} */ (
57503 this.get(ol.GeolocationProperty.ACCURACY));
57504};
57505
57506
57507/**
57508 * Get a geometry of the position accuracy.
57509 * @return {?ol.geom.Polygon} A geometry of the position accuracy.
57510 * @observable
57511 * @api
57512 */
57513ol.Geolocation.prototype.getAccuracyGeometry = function() {
57514 return /** @type {?ol.geom.Polygon} */ (
57515 this.get(ol.GeolocationProperty.ACCURACY_GEOMETRY) || null);
57516};
57517
57518
57519/**
57520 * Get the altitude associated with the position.
57521 * @return {number|undefined} The altitude of the position in meters above mean
57522 * sea level.
57523 * @observable
57524 * @api
57525 */
57526ol.Geolocation.prototype.getAltitude = function() {
57527 return /** @type {number|undefined} */ (
57528 this.get(ol.GeolocationProperty.ALTITUDE));
57529};
57530
57531
57532/**
57533 * Get the altitude accuracy of the position.
57534 * @return {number|undefined} The accuracy of the altitude measurement in
57535 * meters.
57536 * @observable
57537 * @api
57538 */
57539ol.Geolocation.prototype.getAltitudeAccuracy = function() {
57540 return /** @type {number|undefined} */ (
57541 this.get(ol.GeolocationProperty.ALTITUDE_ACCURACY));
57542};
57543
57544
57545/**
57546 * Get the heading as radians clockwise from North.
57547 * @return {number|undefined} The heading of the device in radians from north.
57548 * @observable
57549 * @api
57550 */
57551ol.Geolocation.prototype.getHeading = function() {
57552 return /** @type {number|undefined} */ (
57553 this.get(ol.GeolocationProperty.HEADING));
57554};
57555
57556
57557/**
57558 * Get the position of the device.
57559 * @return {ol.Coordinate|undefined} The current position of the device reported
57560 * in the current projection.
57561 * @observable
57562 * @api
57563 */
57564ol.Geolocation.prototype.getPosition = function() {
57565 return /** @type {ol.Coordinate|undefined} */ (
57566 this.get(ol.GeolocationProperty.POSITION));
57567};
57568
57569
57570/**
57571 * Get the projection associated with the position.
57572 * @return {ol.proj.Projection|undefined} The projection the position is
57573 * reported in.
57574 * @observable
57575 * @api
57576 */
57577ol.Geolocation.prototype.getProjection = function() {
57578 return /** @type {ol.proj.Projection|undefined} */ (
57579 this.get(ol.GeolocationProperty.PROJECTION));
57580};
57581
57582
57583/**
57584 * Get the speed in meters per second.
57585 * @return {number|undefined} The instantaneous speed of the device in meters
57586 * per second.
57587 * @observable
57588 * @api
57589 */
57590ol.Geolocation.prototype.getSpeed = function() {
57591 return /** @type {number|undefined} */ (
57592 this.get(ol.GeolocationProperty.SPEED));
57593};
57594
57595
57596/**
57597 * Determine if the device location is being tracked.
57598 * @return {boolean} The device location is being tracked.
57599 * @observable
57600 * @api
57601 */
57602ol.Geolocation.prototype.getTracking = function() {
57603 return /** @type {boolean} */ (
57604 this.get(ol.GeolocationProperty.TRACKING));
57605};
57606
57607
57608/**
57609 * Get the tracking options.
57610 * @see http://www.w3.org/TR/geolocation-API/#position-options
57611 * @return {GeolocationPositionOptions|undefined} PositionOptions as defined by
57612 * the [HTML5 Geolocation spec
57613 * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
57614 * @observable
57615 * @api
57616 */
57617ol.Geolocation.prototype.getTrackingOptions = function() {
57618 return /** @type {GeolocationPositionOptions|undefined} */ (
57619 this.get(ol.GeolocationProperty.TRACKING_OPTIONS));
57620};
57621
57622
57623/**
57624 * Set the projection to use for transforming the coordinates.
57625 * @param {ol.ProjectionLike} projection The projection the position is
57626 * reported in.
57627 * @observable
57628 * @api
57629 */
57630ol.Geolocation.prototype.setProjection = function(projection) {
57631 this.set(ol.GeolocationProperty.PROJECTION, ol.proj.get(projection));
57632};
57633
57634
57635/**
57636 * Enable or disable tracking.
57637 * @param {boolean} tracking Enable tracking.
57638 * @observable
57639 * @api
57640 */
57641ol.Geolocation.prototype.setTracking = function(tracking) {
57642 this.set(ol.GeolocationProperty.TRACKING, tracking);
57643};
57644
57645
57646/**
57647 * Set the tracking options.
57648 * @see http://www.w3.org/TR/geolocation-API/#position-options
57649 * @param {GeolocationPositionOptions} options PositionOptions as defined by the
57650 * [HTML5 Geolocation spec
57651 * ](http://www.w3.org/TR/geolocation-API/#position_options_interface).
57652 * @observable
57653 * @api
57654 */
57655ol.Geolocation.prototype.setTrackingOptions = function(options) {
57656 this.set(ol.GeolocationProperty.TRACKING_OPTIONS, options);
57657};
57658
57659goog.provide('ol.geom.Circle');
57660
57661goog.require('ol');
57662goog.require('ol.extent');
57663goog.require('ol.geom.GeometryLayout');
57664goog.require('ol.geom.GeometryType');
57665goog.require('ol.geom.SimpleGeometry');
57666goog.require('ol.geom.flat.deflate');
57667
57668
57669/**
57670 * @classdesc
57671 * Circle geometry.
57672 *
57673 * @constructor
57674 * @extends {ol.geom.SimpleGeometry}
57675 * @param {ol.Coordinate} center Center.
57676 * @param {number=} opt_radius Radius.
57677 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
57678 * @api
57679 */
57680ol.geom.Circle = function(center, opt_radius, opt_layout) {
57681 ol.geom.SimpleGeometry.call(this);
57682 var radius = opt_radius ? opt_radius : 0;
57683 this.setCenterAndRadius(center, radius, opt_layout);
57684};
57685ol.inherits(ol.geom.Circle, ol.geom.SimpleGeometry);
57686
57687
57688/**
57689 * Make a complete copy of the geometry.
57690 * @return {!ol.geom.Circle} Clone.
57691 * @override
57692 * @api
57693 */
57694ol.geom.Circle.prototype.clone = function() {
57695 var circle = new ol.geom.Circle(null);
57696 circle.setFlatCoordinates(this.layout, this.flatCoordinates.slice());
57697 return circle;
57698};
57699
57700
57701/**
57702 * @inheritDoc
57703 */
57704ol.geom.Circle.prototype.closestPointXY = function(x, y, closestPoint, minSquaredDistance) {
57705 var flatCoordinates = this.flatCoordinates;
57706 var dx = x - flatCoordinates[0];
57707 var dy = y - flatCoordinates[1];
57708 var squaredDistance = dx * dx + dy * dy;
57709 if (squaredDistance < minSquaredDistance) {
57710 var i;
57711 if (squaredDistance === 0) {
57712 for (i = 0; i < this.stride; ++i) {
57713 closestPoint[i] = flatCoordinates[i];
57714 }
57715 } else {
57716 var delta = this.getRadius() / Math.sqrt(squaredDistance);
57717 closestPoint[0] = flatCoordinates[0] + delta * dx;
57718 closestPoint[1] = flatCoordinates[1] + delta * dy;
57719 for (i = 2; i < this.stride; ++i) {
57720 closestPoint[i] = flatCoordinates[i];
57721 }
57722 }
57723 closestPoint.length = this.stride;
57724 return squaredDistance;
57725 } else {
57726 return minSquaredDistance;
57727 }
57728};
57729
57730
57731/**
57732 * @inheritDoc
57733 */
57734ol.geom.Circle.prototype.containsXY = function(x, y) {
57735 var flatCoordinates = this.flatCoordinates;
57736 var dx = x - flatCoordinates[0];
57737 var dy = y - flatCoordinates[1];
57738 return dx * dx + dy * dy <= this.getRadiusSquared_();
57739};
57740
57741
57742/**
57743 * Return the center of the circle as {@link ol.Coordinate coordinate}.
57744 * @return {ol.Coordinate} Center.
57745 * @api
57746 */
57747ol.geom.Circle.prototype.getCenter = function() {
57748 return this.flatCoordinates.slice(0, this.stride);
57749};
57750
57751
57752/**
57753 * @inheritDoc
57754 */
57755ol.geom.Circle.prototype.computeExtent = function(extent) {
57756 var flatCoordinates = this.flatCoordinates;
57757 var radius = flatCoordinates[this.stride] - flatCoordinates[0];
57758 return ol.extent.createOrUpdate(
57759 flatCoordinates[0] - radius, flatCoordinates[1] - radius,
57760 flatCoordinates[0] + radius, flatCoordinates[1] + radius,
57761 extent);
57762};
57763
57764
57765/**
57766 * Return the radius of the circle.
57767 * @return {number} Radius.
57768 * @api
57769 */
57770ol.geom.Circle.prototype.getRadius = function() {
57771 return Math.sqrt(this.getRadiusSquared_());
57772};
57773
57774
57775/**
57776 * @private
57777 * @return {number} Radius squared.
57778 */
57779ol.geom.Circle.prototype.getRadiusSquared_ = function() {
57780 var dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];
57781 var dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];
57782 return dx * dx + dy * dy;
57783};
57784
57785
57786/**
57787 * @inheritDoc
57788 * @api
57789 */
57790ol.geom.Circle.prototype.getType = function() {
57791 return ol.geom.GeometryType.CIRCLE;
57792};
57793
57794
57795/**
57796 * @inheritDoc
57797 * @api
57798 */
57799ol.geom.Circle.prototype.intersectsExtent = function(extent) {
57800 var circleExtent = this.getExtent();
57801 if (ol.extent.intersects(extent, circleExtent)) {
57802 var center = this.getCenter();
57803
57804 if (extent[0] <= center[0] && extent[2] >= center[0]) {
57805 return true;
57806 }
57807 if (extent[1] <= center[1] && extent[3] >= center[1]) {
57808 return true;
57809 }
57810
57811 return ol.extent.forEachCorner(extent, this.intersectsCoordinate, this);
57812 }
57813 return false;
57814
57815};
57816
57817
57818/**
57819 * Set the center of the circle as {@link ol.Coordinate coordinate}.
57820 * @param {ol.Coordinate} center Center.
57821 * @api
57822 */
57823ol.geom.Circle.prototype.setCenter = function(center) {
57824 var stride = this.stride;
57825 var radius = this.flatCoordinates[stride] - this.flatCoordinates[0];
57826 var flatCoordinates = center.slice();
57827 flatCoordinates[stride] = flatCoordinates[0] + radius;
57828 var i;
57829 for (i = 1; i < stride; ++i) {
57830 flatCoordinates[stride + i] = center[i];
57831 }
57832 this.setFlatCoordinates(this.layout, flatCoordinates);
57833};
57834
57835
57836/**
57837 * Set the center (as {@link ol.Coordinate coordinate}) and the radius (as
57838 * number) of the circle.
57839 * @param {ol.Coordinate} center Center.
57840 * @param {number} radius Radius.
57841 * @param {ol.geom.GeometryLayout=} opt_layout Layout.
57842 * @api
57843 */
57844ol.geom.Circle.prototype.setCenterAndRadius = function(center, radius, opt_layout) {
57845 if (!center) {
57846 this.setFlatCoordinates(ol.geom.GeometryLayout.XY, null);
57847 } else {
57848 this.setLayout(opt_layout, center, 0);
57849 if (!this.flatCoordinates) {
57850 this.flatCoordinates = [];
57851 }
57852 /** @type {Array.<number>} */
57853 var flatCoordinates = this.flatCoordinates;
57854 var offset = ol.geom.flat.deflate.coordinate(
57855 flatCoordinates, 0, center, this.stride);
57856 flatCoordinates[offset++] = flatCoordinates[0] + radius;
57857 var i, ii;
57858 for (i = 1, ii = this.stride; i < ii; ++i) {
57859 flatCoordinates[offset++] = flatCoordinates[i];
57860 }
57861 flatCoordinates.length = offset;
57862 this.changed();
57863 }
57864};
57865
57866
57867/**
57868 * @inheritDoc
57869 */
57870ol.geom.Circle.prototype.getCoordinates = function() {};
57871
57872
57873/**
57874 * @inheritDoc
57875 */
57876ol.geom.Circle.prototype.setCoordinates = function(coordinates, opt_layout) {};
57877
57878
57879/**
57880 * @param {ol.geom.GeometryLayout} layout Layout.
57881 * @param {Array.<number>} flatCoordinates Flat coordinates.
57882 */
57883ol.geom.Circle.prototype.setFlatCoordinates = function(layout, flatCoordinates) {
57884 this.setFlatCoordinatesInternal(layout, flatCoordinates);
57885 this.changed();
57886};
57887
57888
57889/**
57890 * Set the radius of the circle. The radius is in the units of the projection.
57891 * @param {number} radius Radius.
57892 * @api
57893 */
57894ol.geom.Circle.prototype.setRadius = function(radius) {
57895 this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;
57896 this.changed();
57897};
57898
57899
57900/**
57901 * Transform each coordinate of the circle from one coordinate reference system
57902 * to another. The geometry is modified in place.
57903 * If you do not want the geometry modified in place, first clone() it and
57904 * then use this function on the clone.
57905 *
57906 * Internally a circle is currently represented by two points: the center of
57907 * the circle `[cx, cy]`, and the point to the right of the circle
57908 * `[cx + r, cy]`. This `transform` function just transforms these two points.
57909 * So the resulting geometry is also a circle, and that circle does not
57910 * correspond to the shape that would be obtained by transforming every point
57911 * of the original circle.
57912 *
57913 * @param {ol.ProjectionLike} source The current projection. Can be a
57914 * string identifier or a {@link ol.proj.Projection} object.
57915 * @param {ol.ProjectionLike} destination The desired projection. Can be a
57916 * string identifier or a {@link ol.proj.Projection} object.
57917 * @return {ol.geom.Circle} This geometry. Note that original geometry is
57918 * modified in place.
57919 * @function
57920 * @api
57921 */
57922ol.geom.Circle.prototype.transform;
57923
57924goog.provide('ol.geom.flat.geodesic');
57925
57926goog.require('ol.math');
57927goog.require('ol.proj');
57928
57929
57930/**
57931 * @private
57932 * @param {function(number): ol.Coordinate} interpolate Interpolate function.
57933 * @param {ol.TransformFunction} transform Transform from longitude/latitude to
57934 * projected coordinates.
57935 * @param {number} squaredTolerance Squared tolerance.
57936 * @return {Array.<number>} Flat coordinates.
57937 */
57938ol.geom.flat.geodesic.line_ = function(interpolate, transform, squaredTolerance) {
57939 // FIXME reduce garbage generation
57940 // FIXME optimize stack operations
57941
57942 /** @type {Array.<number>} */
57943 var flatCoordinates = [];
57944
57945 var geoA = interpolate(0);
57946 var geoB = interpolate(1);
57947
57948 var a = transform(geoA);
57949 var b = transform(geoB);
57950
57951 /** @type {Array.<ol.Coordinate>} */
57952 var geoStack = [geoB, geoA];
57953 /** @type {Array.<ol.Coordinate>} */
57954 var stack = [b, a];
57955 /** @type {Array.<number>} */
57956 var fractionStack = [1, 0];
57957
57958 /** @type {Object.<string, boolean>} */
57959 var fractions = {};
57960
57961 var maxIterations = 1e5;
57962 var geoM, m, fracA, fracB, fracM, key;
57963
57964 while (--maxIterations > 0 && fractionStack.length > 0) {
57965 // Pop the a coordinate off the stack
57966 fracA = fractionStack.pop();
57967 geoA = geoStack.pop();
57968 a = stack.pop();
57969 // Add the a coordinate if it has not been added yet
57970 key = fracA.toString();
57971 if (!(key in fractions)) {
57972 flatCoordinates.push(a[0], a[1]);
57973 fractions[key] = true;
57974 }
57975 // Pop the b coordinate off the stack
57976 fracB = fractionStack.pop();
57977 geoB = geoStack.pop();
57978 b = stack.pop();
57979 // Find the m point between the a and b coordinates
57980 fracM = (fracA + fracB) / 2;
57981 geoM = interpolate(fracM);
57982 m = transform(geoM);
57983 if (ol.math.squaredSegmentDistance(m[0], m[1], a[0], a[1],
57984 b[0], b[1]) < squaredTolerance) {
57985 // If the m point is sufficiently close to the straight line, then we
57986 // discard it. Just use the b coordinate and move on to the next line
57987 // segment.
57988 flatCoordinates.push(b[0], b[1]);
57989 key = fracB.toString();
57990 fractions[key] = true;
57991 } else {
57992 // Otherwise, we need to subdivide the current line segment. Split it
57993 // into two and push the two line segments onto the stack.
57994 fractionStack.push(fracB, fracM, fracM, fracA);
57995 stack.push(b, m, m, a);
57996 geoStack.push(geoB, geoM, geoM, geoA);
57997 }
57998 }
57999
58000 return flatCoordinates;
58001};
58002
58003
58004/**
58005* Generate a great-circle arcs between two lat/lon points.
58006* @param {number} lon1 Longitude 1 in degrees.
58007* @param {number} lat1 Latitude 1 in degrees.
58008* @param {number} lon2 Longitude 2 in degrees.
58009* @param {number} lat2 Latitude 2 in degrees.
58010 * @param {ol.proj.Projection} projection Projection.
58011* @param {number} squaredTolerance Squared tolerance.
58012* @return {Array.<number>} Flat coordinates.
58013*/
58014ol.geom.flat.geodesic.greatCircleArc = function(
58015 lon1, lat1, lon2, lat2, projection, squaredTolerance) {
58016
58017 var geoProjection = ol.proj.get('EPSG:4326');
58018
58019 var cosLat1 = Math.cos(ol.math.toRadians(lat1));
58020 var sinLat1 = Math.sin(ol.math.toRadians(lat1));
58021 var cosLat2 = Math.cos(ol.math.toRadians(lat2));
58022 var sinLat2 = Math.sin(ol.math.toRadians(lat2));
58023 var cosDeltaLon = Math.cos(ol.math.toRadians(lon2 - lon1));
58024 var sinDeltaLon = Math.sin(ol.math.toRadians(lon2 - lon1));
58025 var d = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDeltaLon;
58026
58027 return ol.geom.flat.geodesic.line_(
58028 /**
58029 * @param {number} frac Fraction.
58030 * @return {ol.Coordinate} Coordinate.
58031 */
58032 function(frac) {
58033 if (1 <= d) {
58034 return [lon2, lat2];
58035 }
58036 var D = frac * Math.acos(d);
58037 var cosD = Math.cos(D);
58038 var sinD = Math.sin(D);
58039 var y = sinDeltaLon * cosLat2;
58040 var x = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDeltaLon;
58041 var theta = Math.atan2(y, x);
58042 var lat = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(theta));
58043 var lon = ol.math.toRadians(lon1) +
58044 Math.atan2(Math.sin(theta) * sinD * cosLat1,
58045 cosD - sinLat1 * Math.sin(lat));
58046 return [ol.math.toDegrees(lon), ol.math.toDegrees(lat)];
58047 }, ol.proj.getTransform(geoProjection, projection), squaredTolerance);
58048};
58049
58050
58051/**
58052 * Generate a meridian (line at constant longitude).
58053 * @param {number} lon Longitude.
58054 * @param {number} lat1 Latitude 1.
58055 * @param {number} lat2 Latitude 2.
58056 * @param {ol.proj.Projection} projection Projection.
58057 * @param {number} squaredTolerance Squared tolerance.
58058 * @return {Array.<number>} Flat coordinates.
58059 */
58060ol.geom.flat.geodesic.meridian = function(lon, lat1, lat2, projection, squaredTolerance) {
58061 var epsg4326Projection = ol.proj.get('EPSG:4326');
58062 return ol.geom.flat.geodesic.line_(
58063 /**
58064 * @param {number} frac Fraction.
58065 * @return {ol.Coordinate} Coordinate.
58066 */
58067 function(frac) {
58068 return [lon, lat1 + ((lat2 - lat1) * frac)];
58069 },
58070 ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
58071};
58072
58073
58074/**
58075 * Generate a parallel (line at constant latitude).
58076 * @param {number} lat Latitude.
58077 * @param {number} lon1 Longitude 1.
58078 * @param {number} lon2 Longitude 2.
58079 * @param {ol.proj.Projection} projection Projection.
58080 * @param {number} squaredTolerance Squared tolerance.
58081 * @return {Array.<number>} Flat coordinates.
58082 */
58083ol.geom.flat.geodesic.parallel = function(lat, lon1, lon2, projection, squaredTolerance) {
58084 var epsg4326Projection = ol.proj.get('EPSG:4326');
58085 return ol.geom.flat.geodesic.line_(
58086 /**
58087 * @param {number} frac Fraction.
58088 * @return {ol.Coordinate} Coordinate.
58089 */
58090 function(frac) {
58091 return [lon1 + ((lon2 - lon1) * frac), lat];
58092 },
58093 ol.proj.getTransform(epsg4326Projection, projection), squaredTolerance);
58094};
58095
58096goog.provide('ol.Graticule');
58097
58098goog.require('ol.coordinate');
58099goog.require('ol.extent');
58100goog.require('ol.geom.GeometryLayout');
58101goog.require('ol.geom.LineString');
58102goog.require('ol.geom.Point');
58103goog.require('ol.geom.flat.geodesic');
58104goog.require('ol.math');
58105goog.require('ol.proj');
58106goog.require('ol.render.EventType');
58107goog.require('ol.style.Fill');
58108goog.require('ol.style.Stroke');
58109goog.require('ol.style.Text');
58110
58111
58112/**
58113 * Render a grid for a coordinate system on a map.
58114 * @constructor
58115 * @param {olx.GraticuleOptions=} opt_options Options.
58116 * @api
58117 */
58118ol.Graticule = function(opt_options) {
58119 var options = opt_options || {};
58120
58121 /**
58122 * @type {ol.Map}
58123 * @private
58124 */
58125 this.map_ = null;
58126
58127 /**
58128 * @type {ol.proj.Projection}
58129 * @private
58130 */
58131 this.projection_ = null;
58132
58133 /**
58134 * @type {number}
58135 * @private
58136 */
58137 this.maxLat_ = Infinity;
58138
58139 /**
58140 * @type {number}
58141 * @private
58142 */
58143 this.maxLon_ = Infinity;
58144
58145 /**
58146 * @type {number}
58147 * @private
58148 */
58149 this.minLat_ = -Infinity;
58150
58151 /**
58152 * @type {number}
58153 * @private
58154 */
58155 this.minLon_ = -Infinity;
58156
58157 /**
58158 * @type {number}
58159 * @private
58160 */
58161 this.maxLatP_ = Infinity;
58162
58163 /**
58164 * @type {number}
58165 * @private
58166 */
58167 this.maxLonP_ = Infinity;
58168
58169 /**
58170 * @type {number}
58171 * @private
58172 */
58173 this.minLatP_ = -Infinity;
58174
58175 /**
58176 * @type {number}
58177 * @private
58178 */
58179 this.minLonP_ = -Infinity;
58180
58181 /**
58182 * @type {number}
58183 * @private
58184 */
58185 this.targetSize_ = options.targetSize !== undefined ?
58186 options.targetSize : 100;
58187
58188 /**
58189 * @type {number}
58190 * @private
58191 */
58192 this.maxLines_ = options.maxLines !== undefined ? options.maxLines : 100;
58193
58194 /**
58195 * @type {Array.<ol.geom.LineString>}
58196 * @private
58197 */
58198 this.meridians_ = [];
58199
58200 /**
58201 * @type {Array.<ol.geom.LineString>}
58202 * @private
58203 */
58204 this.parallels_ = [];
58205
58206 /**
58207 * @type {ol.style.Stroke}
58208 * @private
58209 */
58210 this.strokeStyle_ = options.strokeStyle !== undefined ?
58211 options.strokeStyle : ol.Graticule.DEFAULT_STROKE_STYLE_;
58212
58213 /**
58214 * @type {ol.TransformFunction|undefined}
58215 * @private
58216 */
58217 this.fromLonLatTransform_ = undefined;
58218
58219 /**
58220 * @type {ol.TransformFunction|undefined}
58221 * @private
58222 */
58223 this.toLonLatTransform_ = undefined;
58224
58225 /**
58226 * @type {ol.Coordinate}
58227 * @private
58228 */
58229 this.projectionCenterLonLat_ = null;
58230
58231 /**
58232 * @type {Array.<ol.GraticuleLabelDataType>}
58233 * @private
58234 */
58235 this.meridiansLabels_ = null;
58236
58237 /**
58238 * @type {Array.<ol.GraticuleLabelDataType>}
58239 * @private
58240 */
58241 this.parallelsLabels_ = null;
58242
58243 if (options.showLabels == true) {
58244 var degreesToString = ol.coordinate.degreesToStringHDMS;
58245
58246 /**
58247 * @type {null|function(number):string}
58248 * @private
58249 */
58250 this.lonLabelFormatter_ = options.lonLabelFormatter == undefined ?
58251 degreesToString.bind(this, 'EW') : options.lonLabelFormatter;
58252
58253 /**
58254 * @type {function(number):string}
58255 * @private
58256 */
58257 this.latLabelFormatter_ = options.latLabelFormatter == undefined ?
58258 degreesToString.bind(this, 'NS') : options.latLabelFormatter;
58259
58260 /**
58261 * Longitude label position in fractions (0..1) of view extent. 0 means
58262 * bottom, 1 means top.
58263 * @type {number}
58264 * @private
58265 */
58266 this.lonLabelPosition_ = options.lonLabelPosition == undefined ? 0 :
58267 options.lonLabelPosition;
58268
58269 /**
58270 * Latitude Label position in fractions (0..1) of view extent. 0 means left, 1
58271 * means right.
58272 * @type {number}
58273 * @private
58274 */
58275 this.latLabelPosition_ = options.latLabelPosition == undefined ? 1 :
58276 options.latLabelPosition;
58277
58278 /**
58279 * @type {ol.style.Text}
58280 * @private
58281 */
58282 this.lonLabelStyle_ = options.lonLabelStyle !== undefined ? options.lonLabelStyle :
58283 new ol.style.Text({
58284 font: '12px Calibri,sans-serif',
58285 textBaseline: 'bottom',
58286 fill: new ol.style.Fill({
58287 color: 'rgba(0,0,0,1)'
58288 }),
58289 stroke: new ol.style.Stroke({
58290 color: 'rgba(255,255,255,1)',
58291 width: 3
58292 })
58293 });
58294
58295 /**
58296 * @type {ol.style.Text}
58297 * @private
58298 */
58299 this.latLabelStyle_ = options.latLabelStyle !== undefined ? options.latLabelStyle :
58300 new ol.style.Text({
58301 font: '12px Calibri,sans-serif',
58302 textAlign: 'end',
58303 fill: new ol.style.Fill({
58304 color: 'rgba(0,0,0,1)'
58305 }),
58306 stroke: new ol.style.Stroke({
58307 color: 'rgba(255,255,255,1)',
58308 width: 3
58309 })
58310 });
58311
58312 this.meridiansLabels_ = [];
58313 this.parallelsLabels_ = [];
58314 }
58315
58316 this.setMap(options.map !== undefined ? options.map : null);
58317};
58318
58319
58320/**
58321 * @type {ol.style.Stroke}
58322 * @private
58323 * @const
58324 */
58325ol.Graticule.DEFAULT_STROKE_STYLE_ = new ol.style.Stroke({
58326 color: 'rgba(0,0,0,0.2)'
58327});
58328
58329
58330/**
58331 * TODO can be configurable
58332 * @type {Array.<number>}
58333 * @private
58334 */
58335ol.Graticule.intervals_ = [90, 45, 30, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05,
58336 0.01, 0.005, 0.002, 0.001];
58337
58338
58339/**
58340 * @param {number} lon Longitude.
58341 * @param {number} minLat Minimal latitude.
58342 * @param {number} maxLat Maximal latitude.
58343 * @param {number} squaredTolerance Squared tolerance.
58344 * @param {ol.Extent} extent Extent.
58345 * @param {number} index Index.
58346 * @return {number} Index.
58347 * @private
58348 */
58349ol.Graticule.prototype.addMeridian_ = function(lon, minLat, maxLat, squaredTolerance, extent, index) {
58350 var lineString = this.getMeridian_(lon, minLat, maxLat,
58351 squaredTolerance, index);
58352 if (ol.extent.intersects(lineString.getExtent(), extent)) {
58353 if (this.meridiansLabels_) {
58354 var textPoint = this.getMeridianPoint_(lineString, extent, index);
58355 this.meridiansLabels_[index] = {
58356 geom: textPoint,
58357 text: this.lonLabelFormatter_(lon)
58358 };
58359 }
58360 this.meridians_[index++] = lineString;
58361 }
58362 return index;
58363};
58364
58365/**
58366 * @param {ol.geom.LineString} lineString Meridian
58367 * @param {ol.Extent} extent Extent.
58368 * @param {number} index Index.
58369 * @return {ol.geom.Point} Meridian point.
58370 * @private
58371 */
58372ol.Graticule.prototype.getMeridianPoint_ = function(lineString, extent, index) {
58373 var flatCoordinates = lineString.getFlatCoordinates();
58374 var clampedBottom = Math.max(extent[1], flatCoordinates[1]);
58375 var clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 1]);
58376 var lat = ol.math.clamp(
58377 extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
58378 clampedBottom, clampedTop);
58379 var coordinate = [flatCoordinates[0], lat];
58380 var point = this.meridiansLabels_[index] !== undefined ?
58381 this.meridiansLabels_[index].geom : new ol.geom.Point(null);
58382 point.setCoordinates(coordinate);
58383 return point;
58384};
58385
58386
58387/**
58388 * @param {number} lat Latitude.
58389 * @param {number} minLon Minimal longitude.
58390 * @param {number} maxLon Maximal longitude.
58391 * @param {number} squaredTolerance Squared tolerance.
58392 * @param {ol.Extent} extent Extent.
58393 * @param {number} index Index.
58394 * @return {number} Index.
58395 * @private
58396 */
58397ol.Graticule.prototype.addParallel_ = function(lat, minLon, maxLon, squaredTolerance, extent, index) {
58398 var lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance,
58399 index);
58400 if (ol.extent.intersects(lineString.getExtent(), extent)) {
58401 if (this.parallelsLabels_) {
58402 var textPoint = this.getParallelPoint_(lineString, extent, index);
58403 this.parallelsLabels_[index] = {
58404 geom: textPoint,
58405 text: this.latLabelFormatter_(lat)
58406 };
58407 }
58408 this.parallels_[index++] = lineString;
58409 }
58410 return index;
58411};
58412
58413
58414/**
58415 * @param {ol.geom.LineString} lineString Parallels.
58416 * @param {ol.Extent} extent Extent.
58417 * @param {number} index Index.
58418 * @return {ol.geom.Point} Parallel point.
58419 * @private
58420 */
58421ol.Graticule.prototype.getParallelPoint_ = function(lineString, extent, index) {
58422 var flatCoordinates = lineString.getFlatCoordinates();
58423 var clampedLeft = Math.max(extent[0], flatCoordinates[0]);
58424 var clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);
58425 var lon = ol.math.clamp(
58426 extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
58427 clampedLeft, clampedRight);
58428 var coordinate = [lon, flatCoordinates[1]];
58429 var point = this.parallelsLabels_[index] !== undefined ?
58430 this.parallelsLabels_[index].geom : new ol.geom.Point(null);
58431 point.setCoordinates(coordinate);
58432 return point;
58433};
58434
58435
58436/**
58437 * @param {ol.Extent} extent Extent.
58438 * @param {ol.Coordinate} center Center.
58439 * @param {number} resolution Resolution.
58440 * @param {number} squaredTolerance Squared tolerance.
58441 * @private
58442 */
58443ol.Graticule.prototype.createGraticule_ = function(extent, center, resolution, squaredTolerance) {
58444
58445 var interval = this.getInterval_(resolution);
58446 if (interval == -1) {
58447 this.meridians_.length = this.parallels_.length = 0;
58448 if (this.meridiansLabels_) {
58449 this.meridiansLabels_.length = 0;
58450 }
58451 if (this.parallelsLabels_) {
58452 this.parallelsLabels_.length = 0;
58453 }
58454 return;
58455 }
58456
58457 var centerLonLat = this.toLonLatTransform_(center);
58458 var centerLon = centerLonLat[0];
58459 var centerLat = centerLonLat[1];
58460 var maxLines = this.maxLines_;
58461 var cnt, idx, lat, lon;
58462
58463 var validExtent = [
58464 Math.max(extent[0], this.minLonP_),
58465 Math.max(extent[1], this.minLatP_),
58466 Math.min(extent[2], this.maxLonP_),
58467 Math.min(extent[3], this.maxLatP_)
58468 ];
58469
58470 validExtent = ol.proj.transformExtent(validExtent, this.projection_,
58471 'EPSG:4326');
58472 var maxLat = validExtent[3];
58473 var maxLon = validExtent[2];
58474 var minLat = validExtent[1];
58475 var minLon = validExtent[0];
58476
58477 // Create meridians
58478
58479 centerLon = Math.floor(centerLon / interval) * interval;
58480 lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);
58481
58482 idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, 0);
58483
58484 cnt = 0;
58485 while (lon != this.minLon_ && cnt++ < maxLines) {
58486 lon = Math.max(lon - interval, this.minLon_);
58487 idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
58488 }
58489
58490 lon = ol.math.clamp(centerLon, this.minLon_, this.maxLon_);
58491
58492 cnt = 0;
58493 while (lon != this.maxLon_ && cnt++ < maxLines) {
58494 lon = Math.min(lon + interval, this.maxLon_);
58495 idx = this.addMeridian_(lon, minLat, maxLat, squaredTolerance, extent, idx);
58496 }
58497
58498 this.meridians_.length = idx;
58499 if (this.meridiansLabels_) {
58500 this.meridiansLabels_.length = idx;
58501 }
58502
58503 // Create parallels
58504
58505 centerLat = Math.floor(centerLat / interval) * interval;
58506 lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);
58507
58508 idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, 0);
58509
58510 cnt = 0;
58511 while (lat != this.minLat_ && cnt++ < maxLines) {
58512 lat = Math.max(lat - interval, this.minLat_);
58513 idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);
58514 }
58515
58516 lat = ol.math.clamp(centerLat, this.minLat_, this.maxLat_);
58517
58518 cnt = 0;
58519 while (lat != this.maxLat_ && cnt++ < maxLines) {
58520 lat = Math.min(lat + interval, this.maxLat_);
58521 idx = this.addParallel_(lat, minLon, maxLon, squaredTolerance, extent, idx);
58522 }
58523
58524 this.parallels_.length = idx;
58525 if (this.parallelsLabels_) {
58526 this.parallelsLabels_.length = idx;
58527 }
58528
58529};
58530
58531
58532/**
58533 * @param {number} resolution Resolution.
58534 * @return {number} The interval in degrees.
58535 * @private
58536 */
58537ol.Graticule.prototype.getInterval_ = function(resolution) {
58538 var centerLon = this.projectionCenterLonLat_[0];
58539 var centerLat = this.projectionCenterLonLat_[1];
58540 var interval = -1;
58541 var i, ii, delta, dist;
58542 var target = Math.pow(this.targetSize_ * resolution, 2);
58543 /** @type {Array.<number>} **/
58544 var p1 = [];
58545 /** @type {Array.<number>} **/
58546 var p2 = [];
58547 for (i = 0, ii = ol.Graticule.intervals_.length; i < ii; ++i) {
58548 delta = ol.Graticule.intervals_[i] / 2;
58549 p1[0] = centerLon - delta;
58550 p1[1] = centerLat - delta;
58551 p2[0] = centerLon + delta;
58552 p2[1] = centerLat + delta;
58553 this.fromLonLatTransform_(p1, p1);
58554 this.fromLonLatTransform_(p2, p2);
58555 dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
58556 if (dist <= target) {
58557 break;
58558 }
58559 interval = ol.Graticule.intervals_[i];
58560 }
58561 return interval;
58562};
58563
58564
58565/**
58566 * Get the map associated with this graticule.
58567 * @return {ol.Map} The map.
58568 * @api
58569 */
58570ol.Graticule.prototype.getMap = function() {
58571 return this.map_;
58572};
58573
58574
58575/**
58576 * @param {number} lon Longitude.
58577 * @param {number} minLat Minimal latitude.
58578 * @param {number} maxLat Maximal latitude.
58579 * @param {number} squaredTolerance Squared tolerance.
58580 * @return {ol.geom.LineString} The meridian line string.
58581 * @param {number} index Index.
58582 * @private
58583 */
58584ol.Graticule.prototype.getMeridian_ = function(lon, minLat, maxLat,
58585 squaredTolerance, index) {
58586 var flatCoordinates = ol.geom.flat.geodesic.meridian(lon,
58587 minLat, maxLat, this.projection_, squaredTolerance);
58588 var lineString = this.meridians_[index] !== undefined ?
58589 this.meridians_[index] : new ol.geom.LineString(null);
58590 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
58591 return lineString;
58592};
58593
58594
58595/**
58596 * Get the list of meridians. Meridians are lines of equal longitude.
58597 * @return {Array.<ol.geom.LineString>} The meridians.
58598 * @api
58599 */
58600ol.Graticule.prototype.getMeridians = function() {
58601 return this.meridians_;
58602};
58603
58604
58605/**
58606 * @param {number} lat Latitude.
58607 * @param {number} minLon Minimal longitude.
58608 * @param {number} maxLon Maximal longitude.
58609 * @param {number} squaredTolerance Squared tolerance.
58610 * @return {ol.geom.LineString} The parallel line string.
58611 * @param {number} index Index.
58612 * @private
58613 */
58614ol.Graticule.prototype.getParallel_ = function(lat, minLon, maxLon,
58615 squaredTolerance, index) {
58616 var flatCoordinates = ol.geom.flat.geodesic.parallel(lat,
58617 minLon, maxLon, this.projection_, squaredTolerance);
58618 var lineString = this.parallels_[index] !== undefined ?
58619 this.parallels_[index] : new ol.geom.LineString(null);
58620 lineString.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates);
58621 return lineString;
58622};
58623
58624
58625/**
58626 * Get the list of parallels. Parallels are lines of equal latitude.
58627 * @return {Array.<ol.geom.LineString>} The parallels.
58628 * @api
58629 */
58630ol.Graticule.prototype.getParallels = function() {
58631 return this.parallels_;
58632};
58633
58634
58635/**
58636 * @param {ol.render.Event} e Event.
58637 * @private
58638 */
58639ol.Graticule.prototype.handlePostCompose_ = function(e) {
58640 var vectorContext = e.vectorContext;
58641 var frameState = e.frameState;
58642 var extent = frameState.extent;
58643 var viewState = frameState.viewState;
58644 var center = viewState.center;
58645 var projection = viewState.projection;
58646 var resolution = viewState.resolution;
58647 var pixelRatio = frameState.pixelRatio;
58648 var squaredTolerance =
58649 resolution * resolution / (4 * pixelRatio * pixelRatio);
58650
58651 var updateProjectionInfo = !this.projection_ ||
58652 !ol.proj.equivalent(this.projection_, projection);
58653
58654 if (updateProjectionInfo) {
58655 this.updateProjectionInfo_(projection);
58656 }
58657
58658 this.createGraticule_(extent, center, resolution, squaredTolerance);
58659
58660 // Draw the lines
58661 vectorContext.setFillStrokeStyle(null, this.strokeStyle_);
58662 var i, l, line;
58663 for (i = 0, l = this.meridians_.length; i < l; ++i) {
58664 line = this.meridians_[i];
58665 vectorContext.drawGeometry(line);
58666 }
58667 for (i = 0, l = this.parallels_.length; i < l; ++i) {
58668 line = this.parallels_[i];
58669 vectorContext.drawGeometry(line);
58670 }
58671 var labelData;
58672 if (this.meridiansLabels_) {
58673 for (i = 0, l = this.meridiansLabels_.length; i < l; ++i) {
58674 labelData = this.meridiansLabels_[i];
58675 this.lonLabelStyle_.setText(labelData.text);
58676 vectorContext.setTextStyle(this.lonLabelStyle_);
58677 vectorContext.drawGeometry(labelData.geom);
58678 }
58679 }
58680 if (this.parallelsLabels_) {
58681 for (i = 0, l = this.parallelsLabels_.length; i < l; ++i) {
58682 labelData = this.parallelsLabels_[i];
58683 this.latLabelStyle_.setText(labelData.text);
58684 vectorContext.setTextStyle(this.latLabelStyle_);
58685 vectorContext.drawGeometry(labelData.geom);
58686 }
58687 }
58688};
58689
58690
58691/**
58692 * @param {ol.proj.Projection} projection Projection.
58693 * @private
58694 */
58695ol.Graticule.prototype.updateProjectionInfo_ = function(projection) {
58696 var epsg4326Projection = ol.proj.get('EPSG:4326');
58697
58698 var extent = projection.getExtent();
58699 var worldExtent = projection.getWorldExtent();
58700 var worldExtentP = ol.proj.transformExtent(worldExtent,
58701 epsg4326Projection, projection);
58702
58703 var maxLat = worldExtent[3];
58704 var maxLon = worldExtent[2];
58705 var minLat = worldExtent[1];
58706 var minLon = worldExtent[0];
58707
58708 var maxLatP = worldExtentP[3];
58709 var maxLonP = worldExtentP[2];
58710 var minLatP = worldExtentP[1];
58711 var minLonP = worldExtentP[0];
58712
58713 this.maxLat_ = maxLat;
58714 this.maxLon_ = maxLon;
58715 this.minLat_ = minLat;
58716 this.minLon_ = minLon;
58717
58718 this.maxLatP_ = maxLatP;
58719 this.maxLonP_ = maxLonP;
58720 this.minLatP_ = minLatP;
58721 this.minLonP_ = minLonP;
58722
58723
58724 this.fromLonLatTransform_ = ol.proj.getTransform(
58725 epsg4326Projection, projection);
58726
58727 this.toLonLatTransform_ = ol.proj.getTransform(
58728 projection, epsg4326Projection);
58729
58730 this.projectionCenterLonLat_ = this.toLonLatTransform_(
58731 ol.extent.getCenter(extent));
58732
58733 this.projection_ = projection;
58734};
58735
58736
58737/**
58738 * Set the map for this graticule. The graticule will be rendered on the
58739 * provided map.
58740 * @param {ol.Map} map Map.
58741 * @api
58742 */
58743ol.Graticule.prototype.setMap = function(map) {
58744 if (this.map_) {
58745 this.map_.un(ol.render.EventType.POSTCOMPOSE,
58746 this.handlePostCompose_, this);
58747 this.map_.render();
58748 }
58749 if (map) {
58750 map.on(ol.render.EventType.POSTCOMPOSE,
58751 this.handlePostCompose_, this);
58752 map.render();
58753 }
58754 this.map_ = map;
58755};
58756
58757goog.provide('ol.ImageBase');
58758
58759goog.require('ol');
58760goog.require('ol.events.EventTarget');
58761goog.require('ol.events.EventType');
58762
58763
58764/**
58765 * @constructor
58766 * @abstract
58767 * @extends {ol.events.EventTarget}
58768 * @param {ol.Extent} extent Extent.
58769 * @param {number|undefined} resolution Resolution.
58770 * @param {number} pixelRatio Pixel ratio.
58771 * @param {ol.ImageState} state State.
58772 * @param {Array.<ol.Attribution>} attributions Attributions.
58773 */
58774ol.ImageBase = function(extent, resolution, pixelRatio, state, attributions) {
58775
58776 ol.events.EventTarget.call(this);
58777
58778 /**
58779 * @private
58780 * @type {Array.<ol.Attribution>}
58781 */
58782 this.attributions_ = attributions;
58783
58784 /**
58785 * @protected
58786 * @type {ol.Extent}
58787 */
58788 this.extent = extent;
58789
58790 /**
58791 * @private
58792 * @type {number}
58793 */
58794 this.pixelRatio_ = pixelRatio;
58795
58796 /**
58797 * @protected
58798 * @type {number|undefined}
58799 */
58800 this.resolution = resolution;
58801
58802 /**
58803 * @protected
58804 * @type {ol.ImageState}
58805 */
58806 this.state = state;
58807
58808};
58809ol.inherits(ol.ImageBase, ol.events.EventTarget);
58810
58811
58812/**
58813 * @protected
58814 */
58815ol.ImageBase.prototype.changed = function() {
58816 this.dispatchEvent(ol.events.EventType.CHANGE);
58817};
58818
58819
58820/**
58821 * @return {Array.<ol.Attribution>} Attributions.
58822 */
58823ol.ImageBase.prototype.getAttributions = function() {
58824 return this.attributions_;
58825};
58826
58827
58828/**
58829 * @return {ol.Extent} Extent.
58830 */
58831ol.ImageBase.prototype.getExtent = function() {
58832 return this.extent;
58833};
58834
58835
58836/**
58837 * @abstract
58838 * @param {Object=} opt_context Object.
58839 * @return {HTMLCanvasElement|Image|HTMLVideoElement} Image.
58840 */
58841ol.ImageBase.prototype.getImage = function(opt_context) {};
58842
58843
58844/**
58845 * @return {number} PixelRatio.
58846 */
58847ol.ImageBase.prototype.getPixelRatio = function() {
58848 return this.pixelRatio_;
58849};
58850
58851
58852/**
58853 * @return {number} Resolution.
58854 */
58855ol.ImageBase.prototype.getResolution = function() {
58856 return /** @type {number} */ (this.resolution);
58857};
58858
58859
58860/**
58861 * @return {ol.ImageState} State.
58862 */
58863ol.ImageBase.prototype.getState = function() {
58864 return this.state;
58865};
58866
58867
58868/**
58869 * Load not yet loaded URI.
58870 * @abstract
58871 */
58872ol.ImageBase.prototype.load = function() {};
58873
58874goog.provide('ol.Image');
58875
58876goog.require('ol');
58877goog.require('ol.ImageBase');
58878goog.require('ol.ImageState');
58879goog.require('ol.events');
58880goog.require('ol.events.EventType');
58881goog.require('ol.extent');
58882goog.require('ol.obj');
58883
58884
58885/**
58886 * @constructor
58887 * @extends {ol.ImageBase}
58888 * @param {ol.Extent} extent Extent.
58889 * @param {number|undefined} resolution Resolution.
58890 * @param {number} pixelRatio Pixel ratio.
58891 * @param {Array.<ol.Attribution>} attributions Attributions.
58892 * @param {string} src Image source URI.
58893 * @param {?string} crossOrigin Cross origin.
58894 * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
58895 */
58896ol.Image = function(extent, resolution, pixelRatio, attributions, src,
58897 crossOrigin, imageLoadFunction) {
58898
58899 ol.ImageBase.call(this, extent, resolution, pixelRatio, ol.ImageState.IDLE,
58900 attributions);
58901
58902 /**
58903 * @private
58904 * @type {string}
58905 */
58906 this.src_ = src;
58907
58908 /**
58909 * @private
58910 * @type {HTMLCanvasElement|Image|HTMLVideoElement}
58911 */
58912 this.image_ = new Image();
58913 if (crossOrigin !== null) {
58914 this.image_.crossOrigin = crossOrigin;
58915 }
58916
58917 /**
58918 * @private
58919 * @type {Object.<number, (HTMLCanvasElement|Image|HTMLVideoElement)>}
58920 */
58921 this.imageByContext_ = {};
58922
58923 /**
58924 * @private
58925 * @type {Array.<ol.EventsKey>}
58926 */
58927 this.imageListenerKeys_ = null;
58928
58929 /**
58930 * @protected
58931 * @type {ol.ImageState}
58932 */
58933 this.state = ol.ImageState.IDLE;
58934
58935 /**
58936 * @private
58937 * @type {ol.ImageLoadFunctionType}
58938 */
58939 this.imageLoadFunction_ = imageLoadFunction;
58940
58941};
58942ol.inherits(ol.Image, ol.ImageBase);
58943
58944
58945/**
58946 * @inheritDoc
58947 * @api
58948 */
58949ol.Image.prototype.getImage = function(opt_context) {
58950 if (opt_context !== undefined) {
58951 var image;
58952 var key = ol.getUid(opt_context);
58953 if (key in this.imageByContext_) {
58954 return this.imageByContext_[key];
58955 } else if (ol.obj.isEmpty(this.imageByContext_)) {
58956 image = this.image_;
58957 } else {
58958 image = /** @type {Image} */ (this.image_.cloneNode(false));
58959 }
58960 this.imageByContext_[key] = image;
58961 return image;
58962 } else {
58963 return this.image_;
58964 }
58965};
58966
58967
58968/**
58969 * Tracks loading or read errors.
58970 *
58971 * @private
58972 */
58973ol.Image.prototype.handleImageError_ = function() {
58974 this.state = ol.ImageState.ERROR;
58975 this.unlistenImage_();
58976 this.changed();
58977};
58978
58979
58980/**
58981 * Tracks successful image load.
58982 *
58983 * @private
58984 */
58985ol.Image.prototype.handleImageLoad_ = function() {
58986 if (this.resolution === undefined) {
58987 this.resolution = ol.extent.getHeight(this.extent) / this.image_.height;
58988 }
58989 this.state = ol.ImageState.LOADED;
58990 this.unlistenImage_();
58991 this.changed();
58992};
58993
58994
58995/**
58996 * Load the image or retry if loading previously failed.
58997 * Loading is taken care of by the tile queue, and calling this method is
58998 * only needed for preloading or for reloading in case of an error.
58999 * @override
59000 * @api
59001 */
59002ol.Image.prototype.load = function() {
59003 if (this.state == ol.ImageState.IDLE || this.state == ol.ImageState.ERROR) {
59004 this.state = ol.ImageState.LOADING;
59005 this.changed();
59006 this.imageListenerKeys_ = [
59007 ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
59008 this.handleImageError_, this),
59009 ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
59010 this.handleImageLoad_, this)
59011 ];
59012 this.imageLoadFunction_(this, this.src_);
59013 }
59014};
59015
59016
59017/**
59018 * @param {HTMLCanvasElement|Image|HTMLVideoElement} image Image.
59019 */
59020ol.Image.prototype.setImage = function(image) {
59021 this.image_ = image;
59022};
59023
59024
59025/**
59026 * Discards event handlers which listen for load completion or errors.
59027 *
59028 * @private
59029 */
59030ol.Image.prototype.unlistenImage_ = function() {
59031 this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
59032 this.imageListenerKeys_ = null;
59033};
59034
59035goog.provide('ol.ImageCanvas');
59036
59037goog.require('ol');
59038goog.require('ol.ImageBase');
59039goog.require('ol.ImageState');
59040
59041
59042/**
59043 * @constructor
59044 * @extends {ol.ImageBase}
59045 * @param {ol.Extent} extent Extent.
59046 * @param {number} resolution Resolution.
59047 * @param {number} pixelRatio Pixel ratio.
59048 * @param {Array.<ol.Attribution>} attributions Attributions.
59049 * @param {HTMLCanvasElement} canvas Canvas.
59050 * @param {ol.ImageCanvasLoader=} opt_loader Optional loader function to
59051 * support asynchronous canvas drawing.
59052 */
59053ol.ImageCanvas = function(extent, resolution, pixelRatio, attributions,
59054 canvas, opt_loader) {
59055
59056 /**
59057 * Optional canvas loader function.
59058 * @type {?ol.ImageCanvasLoader}
59059 * @private
59060 */
59061 this.loader_ = opt_loader !== undefined ? opt_loader : null;
59062
59063 var state = opt_loader !== undefined ?
59064 ol.ImageState.IDLE : ol.ImageState.LOADED;
59065
59066 ol.ImageBase.call(this, extent, resolution, pixelRatio, state, attributions);
59067
59068 /**
59069 * @private
59070 * @type {HTMLCanvasElement}
59071 */
59072 this.canvas_ = canvas;
59073
59074 /**
59075 * @private
59076 * @type {Error}
59077 */
59078 this.error_ = null;
59079
59080};
59081ol.inherits(ol.ImageCanvas, ol.ImageBase);
59082
59083
59084/**
59085 * Get any error associated with asynchronous rendering.
59086 * @return {Error} Any error that occurred during rendering.
59087 */
59088ol.ImageCanvas.prototype.getError = function() {
59089 return this.error_;
59090};
59091
59092
59093/**
59094 * Handle async drawing complete.
59095 * @param {Error} err Any error during drawing.
59096 * @private
59097 */
59098ol.ImageCanvas.prototype.handleLoad_ = function(err) {
59099 if (err) {
59100 this.error_ = err;
59101 this.state = ol.ImageState.ERROR;
59102 } else {
59103 this.state = ol.ImageState.LOADED;
59104 }
59105 this.changed();
59106};
59107
59108
59109/**
59110 * @inheritDoc
59111 */
59112ol.ImageCanvas.prototype.load = function() {
59113 if (this.state == ol.ImageState.IDLE) {
59114 this.state = ol.ImageState.LOADING;
59115 this.changed();
59116 this.loader_(this.handleLoad_.bind(this));
59117 }
59118};
59119
59120
59121/**
59122 * @inheritDoc
59123 */
59124ol.ImageCanvas.prototype.getImage = function(opt_context) {
59125 return this.canvas_;
59126};
59127
59128goog.provide('ol.Tile');
59129
59130goog.require('ol');
59131goog.require('ol.TileState');
59132goog.require('ol.events.EventTarget');
59133goog.require('ol.events.EventType');
59134
59135
59136/**
59137 * @classdesc
59138 * Base class for tiles.
59139 *
59140 * @constructor
59141 * @abstract
59142 * @extends {ol.events.EventTarget}
59143 * @param {ol.TileCoord} tileCoord Tile coordinate.
59144 * @param {ol.TileState} state State.
59145 */
59146ol.Tile = function(tileCoord, state) {
59147
59148 ol.events.EventTarget.call(this);
59149
59150 /**
59151 * @type {ol.TileCoord}
59152 */
59153 this.tileCoord = tileCoord;
59154
59155 /**
59156 * @protected
59157 * @type {ol.TileState}
59158 */
59159 this.state = state;
59160
59161 /**
59162 * An "interim" tile for this tile. The interim tile may be used while this
59163 * one is loading, for "smooth" transitions when changing params/dimensions
59164 * on the source.
59165 * @type {ol.Tile}
59166 */
59167 this.interimTile = null;
59168
59169 /**
59170 * A key assigned to the tile. This is used by the tile source to determine
59171 * if this tile can effectively be used, or if a new tile should be created
59172 * and this one be used as an interim tile for this new tile.
59173 * @type {string}
59174 */
59175 this.key = '';
59176
59177};
59178ol.inherits(ol.Tile, ol.events.EventTarget);
59179
59180
59181/**
59182 * @protected
59183 */
59184ol.Tile.prototype.changed = function() {
59185 this.dispatchEvent(ol.events.EventType.CHANGE);
59186};
59187
59188
59189/**
59190 * @return {string} Key.
59191 */
59192ol.Tile.prototype.getKey = function() {
59193 return this.key + '/' + this.tileCoord;
59194};
59195
59196/**
59197 * Get the interim tile most suitable for rendering using the chain of interim
59198 * tiles. This corresponds to the most recent tile that has been loaded, if no
59199 * such tile exists, the original tile is returned.
59200 * @return {!ol.Tile} Best tile for rendering.
59201 */
59202ol.Tile.prototype.getInterimTile = function() {
59203 if (!this.interimTile) {
59204 //empty chain
59205 return this;
59206 }
59207 var tile = this.interimTile;
59208
59209 // find the first loaded tile and return it. Since the chain is sorted in
59210 // decreasing order of creation time, there is no need to search the remainder
59211 // of the list (all those tiles correspond to older requests and will be
59212 // cleaned up by refreshInterimChain)
59213 do {
59214 if (tile.getState() == ol.TileState.LOADED) {
59215 return tile;
59216 }
59217 tile = tile.interimTile;
59218 } while (tile);
59219
59220 // we can not find a better tile
59221 return this;
59222};
59223
59224/**
59225 * Goes through the chain of interim tiles and discards sections of the chain
59226 * that are no longer relevant.
59227 */
59228ol.Tile.prototype.refreshInterimChain = function() {
59229 if (!this.interimTile) {
59230 return;
59231 }
59232
59233 var tile = this.interimTile;
59234 var prev = this;
59235
59236 do {
59237 if (tile.getState() == ol.TileState.LOADED) {
59238 //we have a loaded tile, we can discard the rest of the list
59239 //we would could abort any LOADING tile request
59240 //older than this tile (i.e. any LOADING tile following this entry in the chain)
59241 tile.interimTile = null;
59242 break;
59243 } else if (tile.getState() == ol.TileState.LOADING) {
59244 //keep this LOADING tile any loaded tiles later in the chain are
59245 //older than this tile, so we're still interested in the request
59246 prev = tile;
59247 } else if (tile.getState() == ol.TileState.IDLE) {
59248 //the head of the list is the most current tile, we don't need
59249 //to start any other requests for this chain
59250 prev.interimTile = tile.interimTile;
59251 } else {
59252 prev = tile;
59253 }
59254 tile = prev.interimTile;
59255 } while (tile);
59256};
59257
59258/**
59259 * Get the tile coordinate for this tile.
59260 * @return {ol.TileCoord} The tile coordinate.
59261 * @api
59262 */
59263ol.Tile.prototype.getTileCoord = function() {
59264 return this.tileCoord;
59265};
59266
59267
59268/**
59269 * @return {ol.TileState} State.
59270 */
59271ol.Tile.prototype.getState = function() {
59272 return this.state;
59273};
59274
59275/**
59276 * @param {ol.TileState} state State.
59277 */
59278ol.Tile.prototype.setState = function(state) {
59279 this.state = state;
59280 this.changed();
59281};
59282
59283/**
59284 * Load the image or retry if loading previously failed.
59285 * Loading is taken care of by the tile queue, and calling this method is
59286 * only needed for preloading or for reloading in case of an error.
59287 * @abstract
59288 * @api
59289 */
59290ol.Tile.prototype.load = function() {};
59291
59292goog.provide('ol.ImageTile');
59293
59294goog.require('ol');
59295goog.require('ol.Tile');
59296goog.require('ol.TileState');
59297goog.require('ol.dom');
59298goog.require('ol.events');
59299goog.require('ol.events.EventType');
59300
59301
59302/**
59303 * @constructor
59304 * @extends {ol.Tile}
59305 * @param {ol.TileCoord} tileCoord Tile coordinate.
59306 * @param {ol.TileState} state State.
59307 * @param {string} src Image source URI.
59308 * @param {?string} crossOrigin Cross origin.
59309 * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
59310 */
59311ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) {
59312
59313 ol.Tile.call(this, tileCoord, state);
59314
59315 /**
59316 * Image URI
59317 *
59318 * @private
59319 * @type {string}
59320 */
59321 this.src_ = src;
59322
59323 /**
59324 * @private
59325 * @type {Image|HTMLCanvasElement}
59326 */
59327 this.image_ = new Image();
59328 if (crossOrigin !== null) {
59329 this.image_.crossOrigin = crossOrigin;
59330 }
59331
59332 /**
59333 * @private
59334 * @type {Array.<ol.EventsKey>}
59335 */
59336 this.imageListenerKeys_ = null;
59337
59338 /**
59339 * @private
59340 * @type {ol.TileLoadFunctionType}
59341 */
59342 this.tileLoadFunction_ = tileLoadFunction;
59343
59344};
59345ol.inherits(ol.ImageTile, ol.Tile);
59346
59347
59348/**
59349 * @inheritDoc
59350 */
59351ol.ImageTile.prototype.disposeInternal = function() {
59352 if (this.state == ol.TileState.LOADING) {
59353 this.unlistenImage_();
59354 this.image_.src = ol.ImageTile.blankImage.toDataURL('image/png');
59355 }
59356 if (this.interimTile) {
59357 this.interimTile.dispose();
59358 }
59359 this.state = ol.TileState.ABORT;
59360 this.changed();
59361 ol.Tile.prototype.disposeInternal.call(this);
59362};
59363
59364
59365/**
59366 * Get the HTML image element for this tile (may be a Canvas, Image, or Video).
59367 * @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
59368 * @api
59369 */
59370ol.ImageTile.prototype.getImage = function() {
59371 return this.image_;
59372};
59373
59374
59375/**
59376 * @inheritDoc
59377 */
59378ol.ImageTile.prototype.getKey = function() {
59379 return this.src_;
59380};
59381
59382
59383/**
59384 * Tracks loading or read errors.
59385 *
59386 * @private
59387 */
59388ol.ImageTile.prototype.handleImageError_ = function() {
59389 this.state = ol.TileState.ERROR;
59390 this.unlistenImage_();
59391 this.image_ = ol.ImageTile.blankImage;
59392 this.changed();
59393};
59394
59395
59396/**
59397 * Tracks successful image load.
59398 *
59399 * @private
59400 */
59401ol.ImageTile.prototype.handleImageLoad_ = function() {
59402 if (this.image_.naturalWidth && this.image_.naturalHeight) {
59403 this.state = ol.TileState.LOADED;
59404 } else {
59405 this.state = ol.TileState.EMPTY;
59406 }
59407 this.unlistenImage_();
59408 this.changed();
59409};
59410
59411
59412/**
59413 * @inheritDoc
59414 * @api
59415 */
59416ol.ImageTile.prototype.load = function() {
59417 if (this.state == ol.TileState.IDLE || this.state == ol.TileState.ERROR) {
59418 this.state = ol.TileState.LOADING;
59419 this.changed();
59420 this.imageListenerKeys_ = [
59421 ol.events.listenOnce(this.image_, ol.events.EventType.ERROR,
59422 this.handleImageError_, this),
59423 ol.events.listenOnce(this.image_, ol.events.EventType.LOAD,
59424 this.handleImageLoad_, this)
59425 ];
59426 this.tileLoadFunction_(this, this.src_);
59427 }
59428};
59429
59430
59431/**
59432 * Discards event handlers which listen for load completion or errors.
59433 *
59434 * @private
59435 */
59436ol.ImageTile.prototype.unlistenImage_ = function() {
59437 this.imageListenerKeys_.forEach(ol.events.unlistenByKey);
59438 this.imageListenerKeys_ = null;
59439};
59440
59441
59442/**
59443 * A blank image.
59444 * @type {HTMLCanvasElement}
59445 */
59446ol.ImageTile.blankImage = (function() {
59447 var ctx = ol.dom.createCanvasContext2D(1, 1);
59448 ctx.fillStyle = 'rgba(0,0,0,0)';
59449 ctx.fillRect(0, 0, 1, 1);
59450 return ctx.canvas;
59451})();
59452
59453// FIXME should handle all geo-referenced data, not just vector data
59454
59455goog.provide('ol.interaction.DragAndDrop');
59456
59457goog.require('ol');
59458goog.require('ol.functions');
59459goog.require('ol.events');
59460goog.require('ol.events.Event');
59461goog.require('ol.events.EventType');
59462goog.require('ol.interaction.Interaction');
59463goog.require('ol.proj');
59464
59465
59466/**
59467 * @classdesc
59468 * Handles input of vector data by drag and drop.
59469 *
59470 * @constructor
59471 * @extends {ol.interaction.Interaction}
59472 * @fires ol.interaction.DragAndDrop.Event
59473 * @param {olx.interaction.DragAndDropOptions=} opt_options Options.
59474 * @api
59475 */
59476ol.interaction.DragAndDrop = function(opt_options) {
59477
59478 var options = opt_options ? opt_options : {};
59479
59480 ol.interaction.Interaction.call(this, {
59481 handleEvent: ol.interaction.DragAndDrop.handleEvent
59482 });
59483
59484 /**
59485 * @private
59486 * @type {Array.<function(new: ol.format.Feature)>}
59487 */
59488 this.formatConstructors_ = options.formatConstructors ?
59489 options.formatConstructors : [];
59490
59491 /**
59492 * @private
59493 * @type {ol.proj.Projection}
59494 */
59495 this.projection_ = options.projection ?
59496 ol.proj.get(options.projection) : null;
59497
59498 /**
59499 * @private
59500 * @type {Array.<ol.EventsKey>}
59501 */
59502 this.dropListenKeys_ = null;
59503
59504 /**
59505 * @private
59506 * @type {ol.source.Vector}
59507 */
59508 this.source_ = options.source || null;
59509
59510 /**
59511 * @private
59512 * @type {Element}
59513 */
59514 this.target = options.target ? options.target : null;
59515
59516};
59517ol.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);
59518
59519
59520/**
59521 * @param {Event} event Event.
59522 * @this {ol.interaction.DragAndDrop}
59523 * @private
59524 */
59525ol.interaction.DragAndDrop.handleDrop_ = function(event) {
59526 var files = event.dataTransfer.files;
59527 var i, ii, file;
59528 for (i = 0, ii = files.length; i < ii; ++i) {
59529 file = files.item(i);
59530 var reader = new FileReader();
59531 reader.addEventListener(ol.events.EventType.LOAD,
59532 this.handleResult_.bind(this, file));
59533 reader.readAsText(file);
59534 }
59535};
59536
59537
59538/**
59539 * @param {Event} event Event.
59540 * @private
59541 */
59542ol.interaction.DragAndDrop.handleStop_ = function(event) {
59543 event.stopPropagation();
59544 event.preventDefault();
59545 event.dataTransfer.dropEffect = 'copy';
59546};
59547
59548
59549/**
59550 * @param {File} file File.
59551 * @param {Event} event Load event.
59552 * @private
59553 */
59554ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, event) {
59555 var result = event.target.result;
59556 var map = this.getMap();
59557 var projection = this.projection_;
59558 if (!projection) {
59559 var view = map.getView();
59560 projection = view.getProjection();
59561 }
59562
59563 var formatConstructors = this.formatConstructors_;
59564 var features = [];
59565 var i, ii;
59566 for (i = 0, ii = formatConstructors.length; i < ii; ++i) {
59567 /**
59568 * Avoid "cannot instantiate abstract class" error.
59569 * @type {Function}
59570 */
59571 var formatConstructor = formatConstructors[i];
59572 /**
59573 * @type {ol.format.Feature}
59574 */
59575 var format = new formatConstructor();
59576 features = this.tryReadFeatures_(format, result, {
59577 featureProjection: projection
59578 });
59579 if (features && features.length > 0) {
59580 break;
59581 }
59582 }
59583 if (this.source_) {
59584 this.source_.clear();
59585 this.source_.addFeatures(features);
59586 }
59587 this.dispatchEvent(
59588 new ol.interaction.DragAndDrop.Event(
59589 ol.interaction.DragAndDrop.EventType_.ADD_FEATURES, file,
59590 features, projection));
59591};
59592
59593
59594/**
59595 * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and
59596 * neither prevents the browser default nor stops event propagation.
59597 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
59598 * @return {boolean} `false` to stop event propagation.
59599 * @this {ol.interaction.DragAndDrop}
59600 * @api
59601 */
59602ol.interaction.DragAndDrop.handleEvent = ol.functions.TRUE;
59603
59604
59605/**
59606 * @private
59607 */
59608ol.interaction.DragAndDrop.prototype.registerListeners_ = function() {
59609 var map = this.getMap();
59610 if (map) {
59611 var dropArea = this.target ? this.target : map.getViewport();
59612 this.dropListenKeys_ = [
59613 ol.events.listen(dropArea, ol.events.EventType.DROP,
59614 ol.interaction.DragAndDrop.handleDrop_, this),
59615 ol.events.listen(dropArea, ol.events.EventType.DRAGENTER,
59616 ol.interaction.DragAndDrop.handleStop_, this),
59617 ol.events.listen(dropArea, ol.events.EventType.DRAGOVER,
59618 ol.interaction.DragAndDrop.handleStop_, this),
59619 ol.events.listen(dropArea, ol.events.EventType.DROP,
59620 ol.interaction.DragAndDrop.handleStop_, this)
59621 ];
59622 }
59623};
59624
59625
59626/**
59627 * @inheritDoc
59628 */
59629ol.interaction.DragAndDrop.prototype.setActive = function(active) {
59630 ol.interaction.Interaction.prototype.setActive.call(this, active);
59631 if (active) {
59632 this.registerListeners_();
59633 } else {
59634 this.unregisterListeners_();
59635 }
59636};
59637
59638
59639/**
59640 * @inheritDoc
59641 */
59642ol.interaction.DragAndDrop.prototype.setMap = function(map) {
59643 this.unregisterListeners_();
59644 ol.interaction.Interaction.prototype.setMap.call(this, map);
59645 if (this.getActive()) {
59646 this.registerListeners_();
59647 }
59648};
59649
59650
59651/**
59652 * @param {ol.format.Feature} format Format.
59653 * @param {string} text Text.
59654 * @param {olx.format.ReadOptions} options Read options.
59655 * @private
59656 * @return {Array.<ol.Feature>} Features.
59657 */
59658ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text, options) {
59659 try {
59660 return format.readFeatures(text, options);
59661 } catch (e) {
59662 return null;
59663 }
59664};
59665
59666
59667/**
59668 * @private
59669 */
59670ol.interaction.DragAndDrop.prototype.unregisterListeners_ = function() {
59671 if (this.dropListenKeys_) {
59672 this.dropListenKeys_.forEach(ol.events.unlistenByKey);
59673 this.dropListenKeys_ = null;
59674 }
59675};
59676
59677
59678/**
59679 * @enum {string}
59680 * @private
59681 */
59682ol.interaction.DragAndDrop.EventType_ = {
59683 /**
59684 * Triggered when features are added
59685 * @event ol.interaction.DragAndDrop.Event#addfeatures
59686 * @api
59687 */
59688 ADD_FEATURES: 'addfeatures'
59689};
59690
59691
59692/**
59693 * @classdesc
59694 * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances
59695 * of this type.
59696 *
59697 * @constructor
59698 * @extends {ol.events.Event}
59699 * @implements {oli.interaction.DragAndDropEvent}
59700 * @param {ol.interaction.DragAndDrop.EventType_} type Type.
59701 * @param {File} file File.
59702 * @param {Array.<ol.Feature>=} opt_features Features.
59703 * @param {ol.proj.Projection=} opt_projection Projection.
59704 */
59705ol.interaction.DragAndDrop.Event = function(type, file, opt_features, opt_projection) {
59706
59707 ol.events.Event.call(this, type);
59708
59709 /**
59710 * The features parsed from dropped data.
59711 * @type {Array.<ol.Feature>|undefined}
59712 * @api
59713 */
59714 this.features = opt_features;
59715
59716 /**
59717 * The dropped file.
59718 * @type {File}
59719 * @api
59720 */
59721 this.file = file;
59722
59723 /**
59724 * The feature projection.
59725 * @type {ol.proj.Projection|undefined}
59726 * @api
59727 */
59728 this.projection = opt_projection;
59729
59730};
59731ol.inherits(ol.interaction.DragAndDrop.Event, ol.events.Event);
59732
59733goog.provide('ol.interaction.DragRotateAndZoom');
59734
59735goog.require('ol');
59736goog.require('ol.RotationConstraint');
59737goog.require('ol.ViewHint');
59738goog.require('ol.events.condition');
59739goog.require('ol.interaction.Interaction');
59740goog.require('ol.interaction.Pointer');
59741
59742
59743/**
59744 * @classdesc
59745 * Allows the user to zoom and rotate the map by clicking and dragging
59746 * on the map. By default, this interaction is limited to when the shift
59747 * key is held down.
59748 *
59749 * This interaction is only supported for mouse devices.
59750 *
59751 * And this interaction is not included in the default interactions.
59752 *
59753 * @constructor
59754 * @extends {ol.interaction.Pointer}
59755 * @param {olx.interaction.DragRotateAndZoomOptions=} opt_options Options.
59756 * @api
59757 */
59758ol.interaction.DragRotateAndZoom = function(opt_options) {
59759
59760 var options = opt_options ? opt_options : {};
59761
59762 ol.interaction.Pointer.call(this, {
59763 handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_,
59764 handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_,
59765 handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_
59766 });
59767
59768 /**
59769 * @private
59770 * @type {ol.EventsConditionType}
59771 */
59772 this.condition_ = options.condition ?
59773 options.condition : ol.events.condition.shiftKeyOnly;
59774
59775 /**
59776 * @private
59777 * @type {number|undefined}
59778 */
59779 this.lastAngle_ = undefined;
59780
59781 /**
59782 * @private
59783 * @type {number|undefined}
59784 */
59785 this.lastMagnitude_ = undefined;
59786
59787 /**
59788 * @private
59789 * @type {number}
59790 */
59791 this.lastScaleDelta_ = 0;
59792
59793 /**
59794 * @private
59795 * @type {number}
59796 */
59797 this.duration_ = options.duration !== undefined ? options.duration : 400;
59798
59799};
59800ol.inherits(ol.interaction.DragRotateAndZoom, ol.interaction.Pointer);
59801
59802
59803/**
59804 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
59805 * @this {ol.interaction.DragRotateAndZoom}
59806 * @private
59807 */
59808ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) {
59809 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
59810 return;
59811 }
59812
59813 var map = mapBrowserEvent.map;
59814 var size = map.getSize();
59815 var offset = mapBrowserEvent.pixel;
59816 var deltaX = offset[0] - size[0] / 2;
59817 var deltaY = size[1] / 2 - offset[1];
59818 var theta = Math.atan2(deltaY, deltaX);
59819 var magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
59820 var view = map.getView();
59821 if (view.getConstraints().rotation !== ol.RotationConstraint.disable && this.lastAngle_ !== undefined) {
59822 var angleDelta = theta - this.lastAngle_;
59823 ol.interaction.Interaction.rotateWithoutConstraints(
59824 view, view.getRotation() - angleDelta);
59825 }
59826 this.lastAngle_ = theta;
59827 if (this.lastMagnitude_ !== undefined) {
59828 var resolution = this.lastMagnitude_ * (view.getResolution() / magnitude);
59829 ol.interaction.Interaction.zoomWithoutConstraints(view, resolution);
59830 }
59831 if (this.lastMagnitude_ !== undefined) {
59832 this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;
59833 }
59834 this.lastMagnitude_ = magnitude;
59835};
59836
59837
59838/**
59839 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
59840 * @return {boolean} Stop drag sequence?
59841 * @this {ol.interaction.DragRotateAndZoom}
59842 * @private
59843 */
59844ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) {
59845 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
59846 return true;
59847 }
59848
59849 var map = mapBrowserEvent.map;
59850 var view = map.getView();
59851 view.setHint(ol.ViewHint.INTERACTING, -1);
59852 var direction = this.lastScaleDelta_ - 1;
59853 ol.interaction.Interaction.rotate(view, view.getRotation());
59854 ol.interaction.Interaction.zoom(view, view.getResolution(),
59855 undefined, this.duration_, direction);
59856 this.lastScaleDelta_ = 0;
59857 return false;
59858};
59859
59860
59861/**
59862 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
59863 * @return {boolean} Start drag sequence?
59864 * @this {ol.interaction.DragRotateAndZoom}
59865 * @private
59866 */
59867ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) {
59868 if (!ol.events.condition.mouseOnly(mapBrowserEvent)) {
59869 return false;
59870 }
59871
59872 if (this.condition_(mapBrowserEvent)) {
59873 mapBrowserEvent.map.getView().setHint(ol.ViewHint.INTERACTING, 1);
59874 this.lastAngle_ = undefined;
59875 this.lastMagnitude_ = undefined;
59876 return true;
59877 } else {
59878 return false;
59879 }
59880};
59881
59882goog.provide('ol.interaction.DrawEventType');
59883
59884
59885/**
59886 * @enum {string}
59887 */
59888ol.interaction.DrawEventType = {
59889 /**
59890 * Triggered upon feature draw start
59891 * @event ol.interaction.Draw.Event#drawstart
59892 * @api
59893 */
59894 DRAWSTART: 'drawstart',
59895 /**
59896 * Triggered upon feature draw end
59897 * @event ol.interaction.Draw.Event#drawend
59898 * @api
59899 */
59900 DRAWEND: 'drawend'
59901};
59902
59903goog.provide('ol.render.canvas.Instruction');
59904
59905/**
59906 * @enum {number}
59907 */
59908ol.render.canvas.Instruction = {
59909 BEGIN_GEOMETRY: 0,
59910 BEGIN_PATH: 1,
59911 CIRCLE: 2,
59912 CLOSE_PATH: 3,
59913 CUSTOM: 4,
59914 DRAW_IMAGE: 5,
59915 DRAW_TEXT: 6,
59916 END_GEOMETRY: 7,
59917 FILL: 8,
59918 MOVE_TO_LINE_TO: 9,
59919 SET_FILL_STYLE: 10,
59920 SET_STROKE_STYLE: 11,
59921 SET_TEXT_STYLE: 12,
59922 STROKE: 13
59923};
59924
59925goog.provide('ol.render.canvas.Replay');
59926
59927goog.require('ol');
59928goog.require('ol.array');
59929goog.require('ol.extent');
59930goog.require('ol.extent.Relationship');
59931goog.require('ol.geom.GeometryType');
59932goog.require('ol.geom.flat.inflate');
59933goog.require('ol.geom.flat.transform');
59934goog.require('ol.has');
59935goog.require('ol.obj');
59936goog.require('ol.render.VectorContext');
59937goog.require('ol.render.canvas.Instruction');
59938goog.require('ol.transform');
59939
59940
59941/**
59942 * @constructor
59943 * @extends {ol.render.VectorContext}
59944 * @param {number} tolerance Tolerance.
59945 * @param {ol.Extent} maxExtent Maximum extent.
59946 * @param {number} resolution Resolution.
59947 * @param {boolean} overlaps The replay can have overlapping geometries.
59948 * @struct
59949 */
59950ol.render.canvas.Replay = function(tolerance, maxExtent, resolution, overlaps) {
59951 ol.render.VectorContext.call(this);
59952
59953 /**
59954 * @protected
59955 * @type {number}
59956 */
59957 this.tolerance = tolerance;
59958
59959 /**
59960 * @protected
59961 * @const
59962 * @type {ol.Extent}
59963 */
59964 this.maxExtent = maxExtent;
59965
59966 /**
59967 * @protected
59968 * @type {boolean}
59969 */
59970 this.overlaps = overlaps;
59971
59972 /**
59973 * @protected
59974 * @type {number}
59975 */
59976 this.maxLineWidth = 0;
59977
59978 /**
59979 * @protected
59980 * @const
59981 * @type {number}
59982 */
59983 this.resolution = resolution;
59984
59985 /**
59986 * @private
59987 * @type {ol.Coordinate}
59988 */
59989 this.fillOrigin_;
59990
59991 /**
59992 * @private
59993 * @type {Array.<*>}
59994 */
59995 this.beginGeometryInstruction1_ = null;
59996
59997 /**
59998 * @private
59999 * @type {Array.<*>}
60000 */
60001 this.beginGeometryInstruction2_ = null;
60002
60003 /**
60004 * @protected
60005 * @type {Array.<*>}
60006 */
60007 this.instructions = [];
60008
60009 /**
60010 * @protected
60011 * @type {Array.<number>}
60012 */
60013 this.coordinates = [];
60014
60015 /**
60016 * @private
60017 * @type {Object.<number,ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>>}
60018 */
60019 this.coordinateCache_ = {};
60020
60021 /**
60022 * @private
60023 * @type {!ol.Transform}
60024 */
60025 this.renderedTransform_ = ol.transform.create();
60026
60027 /**
60028 * @protected
60029 * @type {Array.<*>}
60030 */
60031 this.hitDetectionInstructions = [];
60032
60033 /**
60034 * @private
60035 * @type {Array.<number>}
60036 */
60037 this.pixelCoordinates_ = null;
60038
60039 /**
60040 * @private
60041 * @type {!ol.Transform}
60042 */
60043 this.tmpLocalTransform_ = ol.transform.create();
60044
60045 /**
60046 * @private
60047 * @type {!ol.Transform}
60048 */
60049 this.resetTransform_ = ol.transform.create();
60050};
60051ol.inherits(ol.render.canvas.Replay, ol.render.VectorContext);
60052
60053
60054/**
60055 * @param {Array.<number>} flatCoordinates Flat coordinates.
60056 * @param {number} offset Offset.
60057 * @param {number} end End.
60058 * @param {number} stride Stride.
60059 * @param {boolean} closed Last input coordinate equals first.
60060 * @param {boolean} skipFirst Skip first coordinate.
60061 * @protected
60062 * @return {number} My end.
60063 */
60064ol.render.canvas.Replay.prototype.appendFlatCoordinates = function(flatCoordinates, offset, end, stride, closed, skipFirst) {
60065
60066 var myEnd = this.coordinates.length;
60067 var extent = this.getBufferedMaxExtent();
60068 if (skipFirst) {
60069 offset += stride;
60070 }
60071 var lastCoord = [flatCoordinates[offset], flatCoordinates[offset + 1]];
60072 var nextCoord = [NaN, NaN];
60073 var skipped = true;
60074
60075 var i, lastRel, nextRel;
60076 for (i = offset + stride; i < end; i += stride) {
60077 nextCoord[0] = flatCoordinates[i];
60078 nextCoord[1] = flatCoordinates[i + 1];
60079 nextRel = ol.extent.coordinateRelationship(extent, nextCoord);
60080 if (nextRel !== lastRel) {
60081 if (skipped) {
60082 this.coordinates[myEnd++] = lastCoord[0];
60083 this.coordinates[myEnd++] = lastCoord[1];
60084 }
60085 this.coordinates[myEnd++] = nextCoord[0];
60086 this.coordinates[myEnd++] = nextCoord[1];
60087 skipped = false;
60088 } else if (nextRel === ol.extent.Relationship.INTERSECTING) {
60089 this.coordinates[myEnd++] = nextCoord[0];
60090 this.coordinates[myEnd++] = nextCoord[1];
60091 skipped = false;
60092 } else {
60093 skipped = true;
60094 }
60095 lastCoord[0] = nextCoord[0];
60096 lastCoord[1] = nextCoord[1];
60097 lastRel = nextRel;
60098 }
60099
60100 // Last coordinate equals first or only one point to append:
60101 if ((closed && skipped) || i === offset + stride) {
60102 this.coordinates[myEnd++] = lastCoord[0];
60103 this.coordinates[myEnd++] = lastCoord[1];
60104 }
60105 return myEnd;
60106};
60107
60108
60109/**
60110 * @param {Array.<number>} flatCoordinates Flat coordinates.
60111 * @param {number} offset Offset.
60112 * @param {Array.<number>} ends Ends.
60113 * @param {number} stride Stride.
60114 * @param {Array.<number>} replayEnds Replay ends.
60115 * @return {number} Offset.
60116 */
60117ol.render.canvas.Replay.prototype.drawCustomCoordinates_ = function(flatCoordinates, offset, ends, stride, replayEnds) {
60118 for (var i = 0, ii = ends.length; i < ii; ++i) {
60119 var end = ends[i];
60120 var replayEnd = this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);
60121 replayEnds.push(replayEnd);
60122 offset = end;
60123 }
60124 return offset;
60125};
60126
60127
60128/**
60129 * @inheritDoc.
60130 */
60131ol.render.canvas.Replay.prototype.drawCustom = function(geometry, feature, renderer) {
60132 this.beginGeometry(geometry, feature);
60133 var type = geometry.getType();
60134 var stride = geometry.getStride();
60135 var replayBegin = this.coordinates.length;
60136 var flatCoordinates, replayEnd, replayEnds, replayEndss;
60137 var offset;
60138 if (type == ol.geom.GeometryType.MULTI_POLYGON) {
60139 geometry = /** @type {ol.geom.MultiPolygon} */ (geometry);
60140 flatCoordinates = geometry.getOrientedFlatCoordinates();
60141 replayEndss = [];
60142 var endss = geometry.getEndss();
60143 offset = 0;
60144 for (var i = 0, ii = endss.length; i < ii; ++i) {
60145 var myEnds = [];
60146 offset = this.drawCustomCoordinates_(flatCoordinates, offset, endss[i], stride, myEnds);
60147 replayEndss.push(myEnds);
60148 }
60149 this.instructions.push([ol.render.canvas.Instruction.CUSTOM,
60150 replayBegin, replayEndss, geometry, renderer, ol.geom.flat.inflate.coordinatesss]);
60151 } else if (type == ol.geom.GeometryType.POLYGON || type == ol.geom.GeometryType.MULTI_LINE_STRING) {
60152 replayEnds = [];
60153 flatCoordinates = (type == ol.geom.GeometryType.POLYGON) ?
60154 /** @type {ol.geom.Polygon} */ (geometry).getOrientedFlatCoordinates() :
60155 geometry.getFlatCoordinates();
60156 offset = this.drawCustomCoordinates_(flatCoordinates, 0,
60157 /** @type {ol.geom.Polygon|ol.geom.MultiLineString} */ (geometry).getEnds(),
60158 stride, replayEnds);
60159 this.instructions.push([ol.render.canvas.Instruction.CUSTOM,
60160 replayBegin, replayEnds, geometry, renderer, ol.geom.flat.inflate.coordinatess]);
60161 } else if (type == ol.geom.GeometryType.LINE_STRING || type == ol.geom.GeometryType.MULTI_POINT) {
60162 flatCoordinates = geometry.getFlatCoordinates();
60163 replayEnd = this.appendFlatCoordinates(
60164 flatCoordinates, 0, flatCoordinates.length, stride, false, false);
60165 this.instructions.push([ol.render.canvas.Instruction.CUSTOM,
60166 replayBegin, replayEnd, geometry, renderer, ol.geom.flat.inflate.coordinates]);
60167 } else if (type == ol.geom.GeometryType.POINT) {
60168 flatCoordinates = geometry.getFlatCoordinates();
60169 this.coordinates.push(flatCoordinates[0], flatCoordinates[1]);
60170 replayEnd = this.coordinates.length;
60171 this.instructions.push([ol.render.canvas.Instruction.CUSTOM,
60172 replayBegin, replayEnd, geometry, renderer]);
60173 }
60174 this.endGeometry(geometry, feature);
60175};
60176
60177
60178/**
60179 * @protected
60180 * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
60181 * @param {ol.Feature|ol.render.Feature} feature Feature.
60182 */
60183ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) {
60184 this.beginGeometryInstruction1_ =
60185 [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];
60186 this.instructions.push(this.beginGeometryInstruction1_);
60187 this.beginGeometryInstruction2_ =
60188 [ol.render.canvas.Instruction.BEGIN_GEOMETRY, feature, 0];
60189 this.hitDetectionInstructions.push(this.beginGeometryInstruction2_);
60190};
60191
60192
60193/**
60194 * @private
60195 * @param {CanvasRenderingContext2D} context Context.
60196 * @param {number} rotation Rotation.
60197 */
60198ol.render.canvas.Replay.prototype.fill_ = function(context, rotation) {
60199 if (this.fillOrigin_) {
60200 var origin = ol.transform.apply(this.renderedTransform_, this.fillOrigin_.slice());
60201 context.translate(origin[0], origin[1]);
60202 context.rotate(rotation);
60203 }
60204 context.fill();
60205 if (this.fillOrigin_) {
60206 context.setTransform.apply(context, this.resetTransform_);
60207 }
60208};
60209
60210
60211/**
60212 * @private
60213 * @param {CanvasRenderingContext2D} context Context.
60214 * @param {number} pixelRatio Pixel ratio.
60215 * @param {ol.Transform} transform Transform.
60216 * @param {number} viewRotation View rotation.
60217 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
60218 * to skip.
60219 * @param {Array.<*>} instructions Instructions array.
60220 * @param {function((ol.Feature|ol.render.Feature)): T|undefined}
60221 * featureCallback Feature callback.
60222 * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
60223 * extent.
60224 * @return {T|undefined} Callback result.
60225 * @template T
60226 */
60227ol.render.canvas.Replay.prototype.replay_ = function(
60228 context, pixelRatio, transform, viewRotation, skippedFeaturesHash,
60229 instructions, featureCallback, opt_hitExtent) {
60230 /** @type {Array.<number>} */
60231 var pixelCoordinates;
60232 if (this.pixelCoordinates_ && ol.array.equals(transform, this.renderedTransform_)) {
60233 pixelCoordinates = this.pixelCoordinates_;
60234 } else {
60235 if (!this.pixelCoordinates_) {
60236 this.pixelCoordinates_ = [];
60237 }
60238 pixelCoordinates = ol.geom.flat.transform.transform2D(
60239 this.coordinates, 0, this.coordinates.length, 2,
60240 transform, this.pixelCoordinates_);
60241 ol.transform.setFromArray(this.renderedTransform_, transform);
60242 }
60243 var skipFeatures = !ol.obj.isEmpty(skippedFeaturesHash);
60244 var i = 0; // instruction index
60245 var ii = instructions.length; // end of instructions
60246 var d = 0; // data index
60247 var dd; // end of per-instruction data
60248 var localTransform = this.tmpLocalTransform_;
60249 var resetTransform = this.resetTransform_;
60250 var prevX, prevY, roundX, roundY;
60251 var pendingFill = 0;
60252 var pendingStroke = 0;
60253 var coordinateCache = this.coordinateCache_;
60254
60255 var state = /** @type {olx.render.State} */ ({
60256 context: context,
60257 pixelRatio: pixelRatio,
60258 resolution: this.resolution,
60259 rotation: viewRotation
60260 });
60261
60262 // When the batch size gets too big, performance decreases. 200 is a good
60263 // balance between batch size and number of fill/stroke instructions.
60264 var batchSize =
60265 this.instructions != instructions || this.overlaps ? 0 : 200;
60266 while (i < ii) {
60267 var instruction = instructions[i];
60268 var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
60269 var /** @type {ol.Feature|ol.render.Feature} */ feature, fill, stroke, text, x, y;
60270 switch (type) {
60271 case ol.render.canvas.Instruction.BEGIN_GEOMETRY:
60272 feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);
60273 if ((skipFeatures &&
60274 skippedFeaturesHash[ol.getUid(feature).toString()]) ||
60275 !feature.getGeometry()) {
60276 i = /** @type {number} */ (instruction[2]);
60277 } else if (opt_hitExtent !== undefined && !ol.extent.intersects(
60278 opt_hitExtent, feature.getGeometry().getExtent())) {
60279 i = /** @type {number} */ (instruction[2]) + 1;
60280 } else {
60281 ++i;
60282 }
60283 break;
60284 case ol.render.canvas.Instruction.BEGIN_PATH:
60285 if (pendingFill > batchSize) {
60286 this.fill_(context, viewRotation);
60287 pendingFill = 0;
60288 }
60289 if (pendingStroke > batchSize) {
60290 context.stroke();
60291 pendingStroke = 0;
60292 }
60293 if (!pendingFill && !pendingStroke) {
60294 context.beginPath();
60295 prevX = prevY = NaN;
60296 }
60297 ++i;
60298 break;
60299 case ol.render.canvas.Instruction.CIRCLE:
60300 d = /** @type {number} */ (instruction[1]);
60301 var x1 = pixelCoordinates[d];
60302 var y1 = pixelCoordinates[d + 1];
60303 var x2 = pixelCoordinates[d + 2];
60304 var y2 = pixelCoordinates[d + 3];
60305 var dx = x2 - x1;
60306 var dy = y2 - y1;
60307 var r = Math.sqrt(dx * dx + dy * dy);
60308 context.moveTo(x1 + r, y1);
60309 context.arc(x1, y1, r, 0, 2 * Math.PI, true);
60310 ++i;
60311 break;
60312 case ol.render.canvas.Instruction.CLOSE_PATH:
60313 context.closePath();
60314 ++i;
60315 break;
60316 case ol.render.canvas.Instruction.CUSTOM:
60317 d = /** @type {number} */ (instruction[1]);
60318 dd = instruction[2];
60319 var geometry = /** @type {ol.geom.SimpleGeometry} */ (instruction[3]);
60320 var renderer = instruction[4];
60321 var fn = instruction.length == 6 ? instruction[5] : undefined;
60322 state.geometry = geometry;
60323 state.feature = feature;
60324 if (!(i in coordinateCache)) {
60325 coordinateCache[i] = [];
60326 }
60327 var coords = coordinateCache[i];
60328 if (fn) {
60329 fn(pixelCoordinates, d, dd, 2, coords);
60330 } else {
60331 coords[0] = pixelCoordinates[d];
60332 coords[1] = pixelCoordinates[d + 1];
60333 coords.length = 2;
60334 }
60335 renderer(coords, state);
60336 ++i;
60337 break;
60338 case ol.render.canvas.Instruction.DRAW_IMAGE:
60339 d = /** @type {number} */ (instruction[1]);
60340 dd = /** @type {number} */ (instruction[2]);
60341 var image = /** @type {HTMLCanvasElement|HTMLVideoElement|Image} */
60342 (instruction[3]);
60343 // Remaining arguments in DRAW_IMAGE are in alphabetical order
60344 var anchorX = /** @type {number} */ (instruction[4]) * pixelRatio;
60345 var anchorY = /** @type {number} */ (instruction[5]) * pixelRatio;
60346 var height = /** @type {number} */ (instruction[6]);
60347 var opacity = /** @type {number} */ (instruction[7]);
60348 var originX = /** @type {number} */ (instruction[8]);
60349 var originY = /** @type {number} */ (instruction[9]);
60350 var rotateWithView = /** @type {boolean} */ (instruction[10]);
60351 var rotation = /** @type {number} */ (instruction[11]);
60352 var scale = /** @type {number} */ (instruction[12]);
60353 var snapToPixel = /** @type {boolean} */ (instruction[13]);
60354 var width = /** @type {number} */ (instruction[14]);
60355 if (rotateWithView) {
60356 rotation += viewRotation;
60357 }
60358 for (; d < dd; d += 2) {
60359 x = pixelCoordinates[d] - anchorX;
60360 y = pixelCoordinates[d + 1] - anchorY;
60361 if (snapToPixel) {
60362 x = Math.round(x);
60363 y = Math.round(y);
60364 }
60365 if (scale != 1 || rotation !== 0) {
60366 var centerX = x + anchorX;
60367 var centerY = y + anchorY;
60368 ol.transform.compose(localTransform,
60369 centerX, centerY, scale, scale, rotation, -centerX, -centerY);
60370 context.setTransform.apply(context, localTransform);
60371 }
60372 var alpha = context.globalAlpha;
60373 if (opacity != 1) {
60374 context.globalAlpha = alpha * opacity;
60375 }
60376
60377 var w = (width + originX > image.width) ? image.width - originX : width;
60378 var h = (height + originY > image.height) ? image.height - originY : height;
60379
60380 context.drawImage(image, originX, originY, w, h,
60381 x, y, w * pixelRatio, h * pixelRatio);
60382
60383 if (opacity != 1) {
60384 context.globalAlpha = alpha;
60385 }
60386 if (scale != 1 || rotation !== 0) {
60387 context.setTransform.apply(context, resetTransform);
60388 }
60389 }
60390 ++i;
60391 break;
60392 case ol.render.canvas.Instruction.DRAW_TEXT:
60393 d = /** @type {number} */ (instruction[1]);
60394 dd = /** @type {number} */ (instruction[2]);
60395 text = /** @type {string} */ (instruction[3]);
60396 var offsetX = /** @type {number} */ (instruction[4]) * pixelRatio;
60397 var offsetY = /** @type {number} */ (instruction[5]) * pixelRatio;
60398 rotation = /** @type {number} */ (instruction[6]);
60399 scale = /** @type {number} */ (instruction[7]) * pixelRatio;
60400 fill = /** @type {boolean} */ (instruction[8]);
60401 stroke = /** @type {boolean} */ (instruction[9]);
60402 rotateWithView = /** @type {boolean} */ (instruction[10]);
60403 if (rotateWithView) {
60404 rotation += viewRotation;
60405 }
60406 for (; d < dd; d += 2) {
60407 x = pixelCoordinates[d] + offsetX;
60408 y = pixelCoordinates[d + 1] + offsetY;
60409 if (scale != 1 || rotation !== 0) {
60410 ol.transform.compose(localTransform, x, y, scale, scale, rotation, -x, -y);
60411 context.setTransform.apply(context, localTransform);
60412 }
60413
60414 // Support multiple lines separated by \n
60415 var lines = text.split('\n');
60416 var numLines = lines.length;
60417 var fontSize, lineY;
60418 if (numLines > 1) {
60419 // Estimate line height using width of capital M, and add padding
60420 fontSize = Math.round(context.measureText('M').width * 1.5);
60421 lineY = y - (((numLines - 1) / 2) * fontSize);
60422 } else {
60423 // No need to calculate line height/offset for a single line
60424 fontSize = 0;
60425 lineY = y;
60426 }
60427
60428 for (var lineIndex = 0; lineIndex < numLines; lineIndex++) {
60429 var line = lines[lineIndex];
60430 if (stroke) {
60431 context.strokeText(line, x, lineY);
60432 }
60433 if (fill) {
60434 context.fillText(line, x, lineY);
60435 }
60436
60437 // Move next line down by fontSize px
60438 lineY = lineY + fontSize;
60439 }
60440
60441 if (scale != 1 || rotation !== 0) {
60442 context.setTransform.apply(context, resetTransform);
60443 }
60444 }
60445 ++i;
60446 break;
60447 case ol.render.canvas.Instruction.END_GEOMETRY:
60448 if (featureCallback !== undefined) {
60449 feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]);
60450 var result = featureCallback(feature);
60451 if (result) {
60452 return result;
60453 }
60454 }
60455 ++i;
60456 break;
60457 case ol.render.canvas.Instruction.FILL:
60458 if (batchSize) {
60459 pendingFill++;
60460 } else {
60461 this.fill_(context, viewRotation);
60462 }
60463 ++i;
60464 break;
60465 case ol.render.canvas.Instruction.MOVE_TO_LINE_TO:
60466 d = /** @type {number} */ (instruction[1]);
60467 dd = /** @type {number} */ (instruction[2]);
60468 x = pixelCoordinates[d];
60469 y = pixelCoordinates[d + 1];
60470 roundX = (x + 0.5) | 0;
60471 roundY = (y + 0.5) | 0;
60472 if (roundX !== prevX || roundY !== prevY) {
60473 context.moveTo(x, y);
60474 prevX = roundX;
60475 prevY = roundY;
60476 }
60477 for (d += 2; d < dd; d += 2) {
60478 x = pixelCoordinates[d];
60479 y = pixelCoordinates[d + 1];
60480 roundX = (x + 0.5) | 0;
60481 roundY = (y + 0.5) | 0;
60482 if (d == dd - 2 || roundX !== prevX || roundY !== prevY) {
60483 context.lineTo(x, y);
60484 prevX = roundX;
60485 prevY = roundY;
60486 }
60487 }
60488 ++i;
60489 break;
60490 case ol.render.canvas.Instruction.SET_FILL_STYLE:
60491 this.fillOrigin_ = instruction[2];
60492
60493 if (pendingFill) {
60494 this.fill_(context, viewRotation);
60495 pendingFill = 0;
60496 if (pendingStroke) {
60497 context.stroke();
60498 pendingStroke = 0;
60499 }
60500 }
60501
60502 context.fillStyle = /** @type {ol.ColorLike} */ (instruction[1]);
60503 ++i;
60504 break;
60505 case ol.render.canvas.Instruction.SET_STROKE_STYLE:
60506 var usePixelRatio = instruction[8] !== undefined ?
60507 instruction[8] : true;
60508 var renderedPixelRatio = instruction[9];
60509
60510 var lineWidth = /** @type {number} */ (instruction[2]);
60511 if (pendingStroke) {
60512 context.stroke();
60513 pendingStroke = 0;
60514 }
60515 context.strokeStyle = /** @type {ol.ColorLike} */ (instruction[1]);
60516 context.lineWidth = usePixelRatio ? lineWidth * pixelRatio : lineWidth;
60517 context.lineCap = /** @type {string} */ (instruction[3]);
60518 context.lineJoin = /** @type {string} */ (instruction[4]);
60519 context.miterLimit = /** @type {number} */ (instruction[5]);
60520 if (ol.has.CANVAS_LINE_DASH) {
60521 var lineDash = /** @type {Array.<number>} */ (instruction[6]);
60522 var lineDashOffset = /** @type {number} */ (instruction[7]);
60523 if (usePixelRatio && pixelRatio !== renderedPixelRatio) {
60524 lineDash = lineDash.map(function(dash) {
60525 return dash * pixelRatio / renderedPixelRatio;
60526 });
60527 lineDashOffset *= pixelRatio / renderedPixelRatio;
60528 instruction[6] = lineDash;
60529 instruction[7] = lineDashOffset;
60530 instruction[9] = pixelRatio;
60531 }
60532 context.lineDashOffset = lineDashOffset;
60533 context.setLineDash(lineDash);
60534 }
60535 ++i;
60536 break;
60537 case ol.render.canvas.Instruction.SET_TEXT_STYLE:
60538 context.font = /** @type {string} */ (instruction[1]);
60539 context.textAlign = /** @type {string} */ (instruction[2]);
60540 context.textBaseline = /** @type {string} */ (instruction[3]);
60541 ++i;
60542 break;
60543 case ol.render.canvas.Instruction.STROKE:
60544 if (batchSize) {
60545 pendingStroke++;
60546 } else {
60547 context.stroke();
60548 }
60549 ++i;
60550 break;
60551 default:
60552 ++i; // consume the instruction anyway, to avoid an infinite loop
60553 break;
60554 }
60555 }
60556 if (pendingFill) {
60557 this.fill_(context, viewRotation);
60558 }
60559 if (pendingStroke) {
60560 context.stroke();
60561 }
60562 return undefined;
60563};
60564
60565
60566/**
60567 * @param {CanvasRenderingContext2D} context Context.
60568 * @param {number} pixelRatio Pixel ratio.
60569 * @param {ol.Transform} transform Transform.
60570 * @param {number} viewRotation View rotation.
60571 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
60572 * to skip.
60573 */
60574ol.render.canvas.Replay.prototype.replay = function(
60575 context, pixelRatio, transform, viewRotation, skippedFeaturesHash) {
60576 var instructions = this.instructions;
60577 this.replay_(context, pixelRatio, transform, viewRotation,
60578 skippedFeaturesHash, instructions, undefined, undefined);
60579};
60580
60581
60582/**
60583 * @param {CanvasRenderingContext2D} context Context.
60584 * @param {ol.Transform} transform Transform.
60585 * @param {number} viewRotation View rotation.
60586 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
60587 * to skip.
60588 * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback
60589 * Feature callback.
60590 * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
60591 * extent.
60592 * @return {T|undefined} Callback result.
60593 * @template T
60594 */
60595ol.render.canvas.Replay.prototype.replayHitDetection = function(
60596 context, transform, viewRotation, skippedFeaturesHash,
60597 opt_featureCallback, opt_hitExtent) {
60598 var instructions = this.hitDetectionInstructions;
60599 return this.replay_(context, 1, transform, viewRotation,
60600 skippedFeaturesHash, instructions, opt_featureCallback, opt_hitExtent);
60601};
60602
60603
60604/**
60605 * Reverse the hit detection instructions.
60606 */
60607ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions = function() {
60608 var hitDetectionInstructions = this.hitDetectionInstructions;
60609 // step 1 - reverse array
60610 hitDetectionInstructions.reverse();
60611 // step 2 - reverse instructions within geometry blocks
60612 var i;
60613 var n = hitDetectionInstructions.length;
60614 var instruction;
60615 var type;
60616 var begin = -1;
60617 for (i = 0; i < n; ++i) {
60618 instruction = hitDetectionInstructions[i];
60619 type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
60620 if (type == ol.render.canvas.Instruction.END_GEOMETRY) {
60621 begin = i;
60622 } else if (type == ol.render.canvas.Instruction.BEGIN_GEOMETRY) {
60623 instruction[2] = i;
60624 ol.array.reverseSubArray(this.hitDetectionInstructions, begin, i);
60625 begin = -1;
60626 }
60627 }
60628};
60629
60630
60631/**
60632 * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
60633 * @param {ol.Feature|ol.render.Feature} feature Feature.
60634 */
60635ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) {
60636 this.beginGeometryInstruction1_[2] = this.instructions.length;
60637 this.beginGeometryInstruction1_ = null;
60638 this.beginGeometryInstruction2_[2] = this.hitDetectionInstructions.length;
60639 this.beginGeometryInstruction2_ = null;
60640 var endGeometryInstruction =
60641 [ol.render.canvas.Instruction.END_GEOMETRY, feature];
60642 this.instructions.push(endGeometryInstruction);
60643 this.hitDetectionInstructions.push(endGeometryInstruction);
60644};
60645
60646
60647/**
60648 * FIXME empty description for jsdoc
60649 */
60650ol.render.canvas.Replay.prototype.finish = ol.nullFunction;
60651
60652
60653/**
60654 * Get the buffered rendering extent. Rendering will be clipped to the extent
60655 * provided to the constructor. To account for symbolizers that may intersect
60656 * this extent, we calculate a buffered extent (e.g. based on stroke width).
60657 * @return {ol.Extent} The buffered rendering extent.
60658 * @protected
60659 */
60660ol.render.canvas.Replay.prototype.getBufferedMaxExtent = function() {
60661 return this.maxExtent;
60662};
60663
60664goog.provide('ol.render.canvas.ImageReplay');
60665
60666goog.require('ol');
60667goog.require('ol.render.canvas.Instruction');
60668goog.require('ol.render.canvas.Replay');
60669
60670
60671/**
60672 * @constructor
60673 * @extends {ol.render.canvas.Replay}
60674 * @param {number} tolerance Tolerance.
60675 * @param {ol.Extent} maxExtent Maximum extent.
60676 * @param {number} resolution Resolution.
60677 * @param {boolean} overlaps The replay can have overlapping geometries.
60678 * @struct
60679 */
60680ol.render.canvas.ImageReplay = function(tolerance, maxExtent, resolution, overlaps) {
60681 ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
60682
60683 /**
60684 * @private
60685 * @type {HTMLCanvasElement|HTMLVideoElement|Image}
60686 */
60687 this.hitDetectionImage_ = null;
60688
60689 /**
60690 * @private
60691 * @type {HTMLCanvasElement|HTMLVideoElement|Image}
60692 */
60693 this.image_ = null;
60694
60695 /**
60696 * @private
60697 * @type {number|undefined}
60698 */
60699 this.anchorX_ = undefined;
60700
60701 /**
60702 * @private
60703 * @type {number|undefined}
60704 */
60705 this.anchorY_ = undefined;
60706
60707 /**
60708 * @private
60709 * @type {number|undefined}
60710 */
60711 this.height_ = undefined;
60712
60713 /**
60714 * @private
60715 * @type {number|undefined}
60716 */
60717 this.opacity_ = undefined;
60718
60719 /**
60720 * @private
60721 * @type {number|undefined}
60722 */
60723 this.originX_ = undefined;
60724
60725 /**
60726 * @private
60727 * @type {number|undefined}
60728 */
60729 this.originY_ = undefined;
60730
60731 /**
60732 * @private
60733 * @type {boolean|undefined}
60734 */
60735 this.rotateWithView_ = undefined;
60736
60737 /**
60738 * @private
60739 * @type {number|undefined}
60740 */
60741 this.rotation_ = undefined;
60742
60743 /**
60744 * @private
60745 * @type {number|undefined}
60746 */
60747 this.scale_ = undefined;
60748
60749 /**
60750 * @private
60751 * @type {boolean|undefined}
60752 */
60753 this.snapToPixel_ = undefined;
60754
60755 /**
60756 * @private
60757 * @type {number|undefined}
60758 */
60759 this.width_ = undefined;
60760
60761};
60762ol.inherits(ol.render.canvas.ImageReplay, ol.render.canvas.Replay);
60763
60764
60765/**
60766 * @param {Array.<number>} flatCoordinates Flat coordinates.
60767 * @param {number} offset Offset.
60768 * @param {number} end End.
60769 * @param {number} stride Stride.
60770 * @private
60771 * @return {number} My end.
60772 */
60773ol.render.canvas.ImageReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) {
60774 return this.appendFlatCoordinates(
60775 flatCoordinates, offset, end, stride, false, false);
60776};
60777
60778
60779/**
60780 * @inheritDoc
60781 */
60782ol.render.canvas.ImageReplay.prototype.drawPoint = function(pointGeometry, feature) {
60783 if (!this.image_) {
60784 return;
60785 }
60786 this.beginGeometry(pointGeometry, feature);
60787 var flatCoordinates = pointGeometry.getFlatCoordinates();
60788 var stride = pointGeometry.getStride();
60789 var myBegin = this.coordinates.length;
60790 var myEnd = this.drawCoordinates_(
60791 flatCoordinates, 0, flatCoordinates.length, stride);
60792 this.instructions.push([
60793 ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
60794 // Remaining arguments to DRAW_IMAGE are in alphabetical order
60795 this.anchorX_, this.anchorY_, this.height_, this.opacity_,
60796 this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
60797 this.scale_, this.snapToPixel_, this.width_
60798 ]);
60799 this.hitDetectionInstructions.push([
60800 ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
60801 this.hitDetectionImage_,
60802 // Remaining arguments to DRAW_IMAGE are in alphabetical order
60803 this.anchorX_, this.anchorY_, this.height_, this.opacity_,
60804 this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
60805 this.scale_, this.snapToPixel_, this.width_
60806 ]);
60807 this.endGeometry(pointGeometry, feature);
60808};
60809
60810
60811/**
60812 * @inheritDoc
60813 */
60814ol.render.canvas.ImageReplay.prototype.drawMultiPoint = function(multiPointGeometry, feature) {
60815 if (!this.image_) {
60816 return;
60817 }
60818 this.beginGeometry(multiPointGeometry, feature);
60819 var flatCoordinates = multiPointGeometry.getFlatCoordinates();
60820 var stride = multiPointGeometry.getStride();
60821 var myBegin = this.coordinates.length;
60822 var myEnd = this.drawCoordinates_(
60823 flatCoordinates, 0, flatCoordinates.length, stride);
60824 this.instructions.push([
60825 ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd, this.image_,
60826 // Remaining arguments to DRAW_IMAGE are in alphabetical order
60827 this.anchorX_, this.anchorY_, this.height_, this.opacity_,
60828 this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
60829 this.scale_, this.snapToPixel_, this.width_
60830 ]);
60831 this.hitDetectionInstructions.push([
60832 ol.render.canvas.Instruction.DRAW_IMAGE, myBegin, myEnd,
60833 this.hitDetectionImage_,
60834 // Remaining arguments to DRAW_IMAGE are in alphabetical order
60835 this.anchorX_, this.anchorY_, this.height_, this.opacity_,
60836 this.originX_, this.originY_, this.rotateWithView_, this.rotation_,
60837 this.scale_, this.snapToPixel_, this.width_
60838 ]);
60839 this.endGeometry(multiPointGeometry, feature);
60840};
60841
60842
60843/**
60844 * @inheritDoc
60845 */
60846ol.render.canvas.ImageReplay.prototype.finish = function() {
60847 this.reverseHitDetectionInstructions();
60848 // FIXME this doesn't really protect us against further calls to draw*Geometry
60849 this.anchorX_ = undefined;
60850 this.anchorY_ = undefined;
60851 this.hitDetectionImage_ = null;
60852 this.image_ = null;
60853 this.height_ = undefined;
60854 this.scale_ = undefined;
60855 this.opacity_ = undefined;
60856 this.originX_ = undefined;
60857 this.originY_ = undefined;
60858 this.rotateWithView_ = undefined;
60859 this.rotation_ = undefined;
60860 this.snapToPixel_ = undefined;
60861 this.width_ = undefined;
60862};
60863
60864
60865/**
60866 * @inheritDoc
60867 */
60868ol.render.canvas.ImageReplay.prototype.setImageStyle = function(imageStyle) {
60869 var anchor = imageStyle.getAnchor();
60870 var size = imageStyle.getSize();
60871 var hitDetectionImage = imageStyle.getHitDetectionImage(1);
60872 var image = imageStyle.getImage(1);
60873 var origin = imageStyle.getOrigin();
60874 this.anchorX_ = anchor[0];
60875 this.anchorY_ = anchor[1];
60876 this.hitDetectionImage_ = hitDetectionImage;
60877 this.image_ = image;
60878 this.height_ = size[1];
60879 this.opacity_ = imageStyle.getOpacity();
60880 this.originX_ = origin[0];
60881 this.originY_ = origin[1];
60882 this.rotateWithView_ = imageStyle.getRotateWithView();
60883 this.rotation_ = imageStyle.getRotation();
60884 this.scale_ = imageStyle.getScale();
60885 this.snapToPixel_ = imageStyle.getSnapToPixel();
60886 this.width_ = size[0];
60887};
60888
60889goog.provide('ol.render.canvas.LineStringReplay');
60890
60891goog.require('ol');
60892goog.require('ol.array');
60893goog.require('ol.colorlike');
60894goog.require('ol.extent');
60895goog.require('ol.render.canvas');
60896goog.require('ol.render.canvas.Instruction');
60897goog.require('ol.render.canvas.Replay');
60898
60899
60900/**
60901 * @constructor
60902 * @extends {ol.render.canvas.Replay}
60903 * @param {number} tolerance Tolerance.
60904 * @param {ol.Extent} maxExtent Maximum extent.
60905 * @param {number} resolution Resolution.
60906 * @param {boolean} overlaps The replay can have overlapping geometries.
60907 * @struct
60908 */
60909ol.render.canvas.LineStringReplay = function(tolerance, maxExtent, resolution, overlaps) {
60910
60911 ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
60912
60913 /**
60914 * @private
60915 * @type {ol.Extent}
60916 */
60917 this.bufferedMaxExtent_ = null;
60918
60919 /**
60920 * @private
60921 * @type {{currentStrokeStyle: (ol.ColorLike|undefined),
60922 * currentLineCap: (string|undefined),
60923 * currentLineDash: Array.<number>,
60924 * currentLineDashOffset: (number|undefined),
60925 * currentLineJoin: (string|undefined),
60926 * currentLineWidth: (number|undefined),
60927 * currentMiterLimit: (number|undefined),
60928 * lastStroke: (number|undefined),
60929 * strokeStyle: (ol.ColorLike|undefined),
60930 * lineCap: (string|undefined),
60931 * lineDash: Array.<number>,
60932 * lineDashOffset: (number|undefined),
60933 * lineJoin: (string|undefined),
60934 * lineWidth: (number|undefined),
60935 * miterLimit: (number|undefined)}|null}
60936 */
60937 this.state_ = {
60938 currentStrokeStyle: undefined,
60939 currentLineCap: undefined,
60940 currentLineDash: null,
60941 currentLineDashOffset: undefined,
60942 currentLineJoin: undefined,
60943 currentLineWidth: undefined,
60944 currentMiterLimit: undefined,
60945 lastStroke: undefined,
60946 strokeStyle: undefined,
60947 lineCap: undefined,
60948 lineDash: null,
60949 lineDashOffset: undefined,
60950 lineJoin: undefined,
60951 lineWidth: undefined,
60952 miterLimit: undefined
60953 };
60954
60955};
60956ol.inherits(ol.render.canvas.LineStringReplay, ol.render.canvas.Replay);
60957
60958
60959/**
60960 * @param {Array.<number>} flatCoordinates Flat coordinates.
60961 * @param {number} offset Offset.
60962 * @param {number} end End.
60963 * @param {number} stride Stride.
60964 * @private
60965 * @return {number} end.
60966 */
60967ol.render.canvas.LineStringReplay.prototype.drawFlatCoordinates_ = function(flatCoordinates, offset, end, stride) {
60968 var myBegin = this.coordinates.length;
60969 var myEnd = this.appendFlatCoordinates(
60970 flatCoordinates, offset, end, stride, false, false);
60971 var moveToLineToInstruction =
60972 [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];
60973 this.instructions.push(moveToLineToInstruction);
60974 this.hitDetectionInstructions.push(moveToLineToInstruction);
60975 return end;
60976};
60977
60978
60979/**
60980 * @inheritDoc
60981 */
60982ol.render.canvas.LineStringReplay.prototype.getBufferedMaxExtent = function() {
60983 if (!this.bufferedMaxExtent_) {
60984 this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
60985 if (this.maxLineWidth > 0) {
60986 var width = this.resolution * (this.maxLineWidth + 1) / 2;
60987 ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
60988 }
60989 }
60990 return this.bufferedMaxExtent_;
60991};
60992
60993
60994/**
60995 * @private
60996 */
60997ol.render.canvas.LineStringReplay.prototype.setStrokeStyle_ = function() {
60998 var state = this.state_;
60999 var strokeStyle = state.strokeStyle;
61000 var lineCap = state.lineCap;
61001 var lineDash = state.lineDash;
61002 var lineDashOffset = state.lineDashOffset;
61003 var lineJoin = state.lineJoin;
61004 var lineWidth = state.lineWidth;
61005 var miterLimit = state.miterLimit;
61006 if (state.currentStrokeStyle != strokeStyle ||
61007 state.currentLineCap != lineCap ||
61008 !ol.array.equals(state.currentLineDash, lineDash) ||
61009 state.currentLineDashOffset != lineDashOffset ||
61010 state.currentLineJoin != lineJoin ||
61011 state.currentLineWidth != lineWidth ||
61012 state.currentMiterLimit != miterLimit) {
61013 if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
61014 this.instructions.push([ol.render.canvas.Instruction.STROKE]);
61015 state.lastStroke = this.coordinates.length;
61016 }
61017 state.lastStroke = 0;
61018 this.instructions.push([
61019 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61020 strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash, lineDashOffset, true, 1
61021 ], [
61022 ol.render.canvas.Instruction.BEGIN_PATH
61023 ]);
61024 state.currentStrokeStyle = strokeStyle;
61025 state.currentLineCap = lineCap;
61026 state.currentLineDash = lineDash;
61027 state.currentLineDashOffset = lineDashOffset;
61028 state.currentLineJoin = lineJoin;
61029 state.currentLineWidth = lineWidth;
61030 state.currentMiterLimit = miterLimit;
61031 }
61032};
61033
61034
61035/**
61036 * @inheritDoc
61037 */
61038ol.render.canvas.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) {
61039 var state = this.state_;
61040 var strokeStyle = state.strokeStyle;
61041 var lineWidth = state.lineWidth;
61042 if (strokeStyle === undefined || lineWidth === undefined) {
61043 return;
61044 }
61045 this.setStrokeStyle_();
61046 this.beginGeometry(lineStringGeometry, feature);
61047 this.hitDetectionInstructions.push([
61048 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61049 state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
61050 state.miterLimit, state.lineDash, state.lineDashOffset, true, 1
61051 ], [
61052 ol.render.canvas.Instruction.BEGIN_PATH
61053 ]);
61054 var flatCoordinates = lineStringGeometry.getFlatCoordinates();
61055 var stride = lineStringGeometry.getStride();
61056 this.drawFlatCoordinates_(flatCoordinates, 0, flatCoordinates.length, stride);
61057 this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);
61058 this.endGeometry(lineStringGeometry, feature);
61059};
61060
61061
61062/**
61063 * @inheritDoc
61064 */
61065ol.render.canvas.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) {
61066 var state = this.state_;
61067 var strokeStyle = state.strokeStyle;
61068 var lineWidth = state.lineWidth;
61069 if (strokeStyle === undefined || lineWidth === undefined) {
61070 return;
61071 }
61072 this.setStrokeStyle_();
61073 this.beginGeometry(multiLineStringGeometry, feature);
61074 this.hitDetectionInstructions.push([
61075 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61076 state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
61077 state.miterLimit, state.lineDash, state.lineDashOffset, true, 1
61078 ], [
61079 ol.render.canvas.Instruction.BEGIN_PATH
61080 ]);
61081 var ends = multiLineStringGeometry.getEnds();
61082 var flatCoordinates = multiLineStringGeometry.getFlatCoordinates();
61083 var stride = multiLineStringGeometry.getStride();
61084 var offset = 0;
61085 var i, ii;
61086 for (i = 0, ii = ends.length; i < ii; ++i) {
61087 offset = this.drawFlatCoordinates_(
61088 flatCoordinates, offset, ends[i], stride);
61089 }
61090 this.hitDetectionInstructions.push([ol.render.canvas.Instruction.STROKE]);
61091 this.endGeometry(multiLineStringGeometry, feature);
61092};
61093
61094
61095/**
61096 * @inheritDoc
61097 */
61098ol.render.canvas.LineStringReplay.prototype.finish = function() {
61099 var state = this.state_;
61100 if (state.lastStroke != undefined && state.lastStroke != this.coordinates.length) {
61101 this.instructions.push([ol.render.canvas.Instruction.STROKE]);
61102 }
61103 this.reverseHitDetectionInstructions();
61104 this.state_ = null;
61105};
61106
61107
61108/**
61109 * @inheritDoc
61110 */
61111ol.render.canvas.LineStringReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
61112 var strokeStyleColor = strokeStyle.getColor();
61113 this.state_.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
61114 strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
61115 var strokeStyleLineCap = strokeStyle.getLineCap();
61116 this.state_.lineCap = strokeStyleLineCap !== undefined ?
61117 strokeStyleLineCap : ol.render.canvas.defaultLineCap;
61118 var strokeStyleLineDash = strokeStyle.getLineDash();
61119 this.state_.lineDash = strokeStyleLineDash ?
61120 strokeStyleLineDash : ol.render.canvas.defaultLineDash;
61121 var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
61122 this.state_.lineDashOffset = strokeStyleLineDashOffset ?
61123 strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
61124 var strokeStyleLineJoin = strokeStyle.getLineJoin();
61125 this.state_.lineJoin = strokeStyleLineJoin !== undefined ?
61126 strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
61127 var strokeStyleWidth = strokeStyle.getWidth();
61128 this.state_.lineWidth = strokeStyleWidth !== undefined ?
61129 strokeStyleWidth : ol.render.canvas.defaultLineWidth;
61130 var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
61131 this.state_.miterLimit = strokeStyleMiterLimit !== undefined ?
61132 strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
61133
61134 if (this.state_.lineWidth > this.maxLineWidth) {
61135 this.maxLineWidth = this.state_.lineWidth;
61136 // invalidate the buffered max extent cache
61137 this.bufferedMaxExtent_ = null;
61138 }
61139};
61140
61141goog.provide('ol.render.canvas.PolygonReplay');
61142
61143goog.require('ol');
61144goog.require('ol.array');
61145goog.require('ol.color');
61146goog.require('ol.colorlike');
61147goog.require('ol.extent');
61148goog.require('ol.geom.flat.simplify');
61149goog.require('ol.render.canvas');
61150goog.require('ol.render.canvas.Instruction');
61151goog.require('ol.render.canvas.Replay');
61152
61153
61154/**
61155 * @constructor
61156 * @extends {ol.render.canvas.Replay}
61157 * @param {number} tolerance Tolerance.
61158 * @param {ol.Extent} maxExtent Maximum extent.
61159 * @param {number} resolution Resolution.
61160 * @param {boolean} overlaps The replay can have overlapping geometries.
61161 * @struct
61162 */
61163ol.render.canvas.PolygonReplay = function(tolerance, maxExtent, resolution, overlaps) {
61164
61165 ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
61166
61167 /**
61168 * @private
61169 * @type {ol.Extent}
61170 */
61171 this.bufferedMaxExtent_ = null;
61172
61173 /**
61174 * @private
61175 * @type {{currentFillStyle: (ol.ColorLike|undefined),
61176 * currentStrokeStyle: (ol.ColorLike|undefined),
61177 * currentLineCap: (string|undefined),
61178 * currentLineDash: Array.<number>,
61179 * currentLineDashOffset: (number|undefined),
61180 * currentLineJoin: (string|undefined),
61181 * currentLineWidth: (number|undefined),
61182 * currentMiterLimit: (number|undefined),
61183 * fillStyle: (ol.ColorLike|undefined),
61184 * strokeStyle: (ol.ColorLike|undefined),
61185 * lineCap: (string|undefined),
61186 * lineDash: Array.<number>,
61187 * lineDashOffset: (number|undefined),
61188 * lineJoin: (string|undefined),
61189 * lineWidth: (number|undefined),
61190 * miterLimit: (number|undefined)}|null}
61191 */
61192 this.state_ = {
61193 currentFillStyle: undefined,
61194 currentStrokeStyle: undefined,
61195 currentLineCap: undefined,
61196 currentLineDash: null,
61197 currentLineDashOffset: undefined,
61198 currentLineJoin: undefined,
61199 currentLineWidth: undefined,
61200 currentMiterLimit: undefined,
61201 fillStyle: undefined,
61202 strokeStyle: undefined,
61203 lineCap: undefined,
61204 lineDash: null,
61205 lineDashOffset: undefined,
61206 lineJoin: undefined,
61207 lineWidth: undefined,
61208 miterLimit: undefined
61209 };
61210
61211};
61212ol.inherits(ol.render.canvas.PolygonReplay, ol.render.canvas.Replay);
61213
61214
61215/**
61216 * @param {Array.<number>} flatCoordinates Flat coordinates.
61217 * @param {number} offset Offset.
61218 * @param {Array.<number>} ends Ends.
61219 * @param {number} stride Stride.
61220 * @private
61221 * @return {number} End.
61222 */
61223ol.render.canvas.PolygonReplay.prototype.drawFlatCoordinatess_ = function(flatCoordinates, offset, ends, stride) {
61224 var state = this.state_;
61225 var fill = state.fillStyle !== undefined;
61226 var stroke = state.strokeStyle != undefined;
61227 var numEnds = ends.length;
61228 var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
61229 this.instructions.push(beginPathInstruction);
61230 this.hitDetectionInstructions.push(beginPathInstruction);
61231 for (var i = 0; i < numEnds; ++i) {
61232 var end = ends[i];
61233 var myBegin = this.coordinates.length;
61234 var myEnd = this.appendFlatCoordinates(
61235 flatCoordinates, offset, end, stride, true, !stroke);
61236 var moveToLineToInstruction =
61237 [ol.render.canvas.Instruction.MOVE_TO_LINE_TO, myBegin, myEnd];
61238 this.instructions.push(moveToLineToInstruction);
61239 this.hitDetectionInstructions.push(moveToLineToInstruction);
61240 if (stroke) {
61241 // Performance optimization: only call closePath() when we have a stroke.
61242 // Otherwise the ring is closed already (see appendFlatCoordinates above).
61243 var closePathInstruction = [ol.render.canvas.Instruction.CLOSE_PATH];
61244 this.instructions.push(closePathInstruction);
61245 this.hitDetectionInstructions.push(closePathInstruction);
61246 }
61247 offset = end;
61248 }
61249 var fillInstruction = [ol.render.canvas.Instruction.FILL];
61250 this.hitDetectionInstructions.push(fillInstruction);
61251 if (fill) {
61252 this.instructions.push(fillInstruction);
61253 }
61254 if (stroke) {
61255 var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
61256 this.instructions.push(strokeInstruction);
61257 this.hitDetectionInstructions.push(strokeInstruction);
61258 }
61259 return offset;
61260};
61261
61262
61263/**
61264 * @inheritDoc
61265 */
61266ol.render.canvas.PolygonReplay.prototype.drawCircle = function(circleGeometry, feature) {
61267 var state = this.state_;
61268 var fillStyle = state.fillStyle;
61269 var strokeStyle = state.strokeStyle;
61270 if (fillStyle === undefined && strokeStyle === undefined) {
61271 return;
61272 }
61273 this.setFillStrokeStyles_(circleGeometry);
61274 this.beginGeometry(circleGeometry, feature);
61275 // always fill the circle for hit detection
61276 this.hitDetectionInstructions.push([
61277 ol.render.canvas.Instruction.SET_FILL_STYLE,
61278 ol.color.asString(ol.render.canvas.defaultFillStyle)
61279 ]);
61280 if (state.strokeStyle !== undefined) {
61281 this.hitDetectionInstructions.push([
61282 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61283 state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
61284 state.miterLimit, state.lineDash, state.lineDashOffset, true, 1
61285 ]);
61286 }
61287 var flatCoordinates = circleGeometry.getFlatCoordinates();
61288 var stride = circleGeometry.getStride();
61289 var myBegin = this.coordinates.length;
61290 this.appendFlatCoordinates(
61291 flatCoordinates, 0, flatCoordinates.length, stride, false, false);
61292 var beginPathInstruction = [ol.render.canvas.Instruction.BEGIN_PATH];
61293 var circleInstruction = [ol.render.canvas.Instruction.CIRCLE, myBegin];
61294 this.instructions.push(beginPathInstruction, circleInstruction);
61295 this.hitDetectionInstructions.push(beginPathInstruction, circleInstruction);
61296 var fillInstruction = [ol.render.canvas.Instruction.FILL];
61297 this.hitDetectionInstructions.push(fillInstruction);
61298 if (state.fillStyle !== undefined) {
61299 this.instructions.push(fillInstruction);
61300 }
61301 if (state.strokeStyle !== undefined) {
61302 var strokeInstruction = [ol.render.canvas.Instruction.STROKE];
61303 this.instructions.push(strokeInstruction);
61304 this.hitDetectionInstructions.push(strokeInstruction);
61305 }
61306 this.endGeometry(circleGeometry, feature);
61307};
61308
61309
61310/**
61311 * @inheritDoc
61312 */
61313ol.render.canvas.PolygonReplay.prototype.drawPolygon = function(polygonGeometry, feature) {
61314 var state = this.state_;
61315 this.setFillStrokeStyles_(polygonGeometry);
61316 this.beginGeometry(polygonGeometry, feature);
61317 // always fill the polygon for hit detection
61318 this.hitDetectionInstructions.push([
61319 ol.render.canvas.Instruction.SET_FILL_STYLE,
61320 ol.color.asString(ol.render.canvas.defaultFillStyle)]
61321 );
61322 if (state.strokeStyle !== undefined) {
61323 this.hitDetectionInstructions.push([
61324 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61325 state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
61326 state.miterLimit, state.lineDash, state.lineDashOffset, true, 1
61327 ]);
61328 }
61329 var ends = polygonGeometry.getEnds();
61330 var flatCoordinates = polygonGeometry.getOrientedFlatCoordinates();
61331 var stride = polygonGeometry.getStride();
61332 this.drawFlatCoordinatess_(flatCoordinates, 0, ends, stride);
61333 this.endGeometry(polygonGeometry, feature);
61334};
61335
61336
61337/**
61338 * @inheritDoc
61339 */
61340ol.render.canvas.PolygonReplay.prototype.drawMultiPolygon = function(multiPolygonGeometry, feature) {
61341 var state = this.state_;
61342 var fillStyle = state.fillStyle;
61343 var strokeStyle = state.strokeStyle;
61344 if (fillStyle === undefined && strokeStyle === undefined) {
61345 return;
61346 }
61347 this.setFillStrokeStyles_(multiPolygonGeometry);
61348 this.beginGeometry(multiPolygonGeometry, feature);
61349 // always fill the multi-polygon for hit detection
61350 this.hitDetectionInstructions.push([
61351 ol.render.canvas.Instruction.SET_FILL_STYLE,
61352 ol.color.asString(ol.render.canvas.defaultFillStyle)
61353 ]);
61354 if (state.strokeStyle !== undefined) {
61355 this.hitDetectionInstructions.push([
61356 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61357 state.strokeStyle, state.lineWidth, state.lineCap, state.lineJoin,
61358 state.miterLimit, state.lineDash, state.lineDashOffset, true, 1
61359 ]);
61360 }
61361 var endss = multiPolygonGeometry.getEndss();
61362 var flatCoordinates = multiPolygonGeometry.getOrientedFlatCoordinates();
61363 var stride = multiPolygonGeometry.getStride();
61364 var offset = 0;
61365 var i, ii;
61366 for (i = 0, ii = endss.length; i < ii; ++i) {
61367 offset = this.drawFlatCoordinatess_(
61368 flatCoordinates, offset, endss[i], stride);
61369 }
61370 this.endGeometry(multiPolygonGeometry, feature);
61371};
61372
61373
61374/**
61375 * @inheritDoc
61376 */
61377ol.render.canvas.PolygonReplay.prototype.finish = function() {
61378 this.reverseHitDetectionInstructions();
61379 this.state_ = null;
61380 // We want to preserve topology when drawing polygons. Polygons are
61381 // simplified using quantization and point elimination. However, we might
61382 // have received a mix of quantized and non-quantized geometries, so ensure
61383 // that all are quantized by quantizing all coordinates in the batch.
61384 var tolerance = this.tolerance;
61385 if (tolerance !== 0) {
61386 var coordinates = this.coordinates;
61387 var i, ii;
61388 for (i = 0, ii = coordinates.length; i < ii; ++i) {
61389 coordinates[i] = ol.geom.flat.simplify.snap(coordinates[i], tolerance);
61390 }
61391 }
61392};
61393
61394
61395/**
61396 * @inheritDoc
61397 */
61398ol.render.canvas.PolygonReplay.prototype.getBufferedMaxExtent = function() {
61399 if (!this.bufferedMaxExtent_) {
61400 this.bufferedMaxExtent_ = ol.extent.clone(this.maxExtent);
61401 if (this.maxLineWidth > 0) {
61402 var width = this.resolution * (this.maxLineWidth + 1) / 2;
61403 ol.extent.buffer(this.bufferedMaxExtent_, width, this.bufferedMaxExtent_);
61404 }
61405 }
61406 return this.bufferedMaxExtent_;
61407};
61408
61409
61410/**
61411 * @inheritDoc
61412 */
61413ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
61414 var state = this.state_;
61415 if (fillStyle) {
61416 var fillStyleColor = fillStyle.getColor();
61417 state.fillStyle = ol.colorlike.asColorLike(fillStyleColor ?
61418 fillStyleColor : ol.render.canvas.defaultFillStyle);
61419 } else {
61420 state.fillStyle = undefined;
61421 }
61422 if (strokeStyle) {
61423 var strokeStyleColor = strokeStyle.getColor();
61424 state.strokeStyle = ol.colorlike.asColorLike(strokeStyleColor ?
61425 strokeStyleColor : ol.render.canvas.defaultStrokeStyle);
61426 var strokeStyleLineCap = strokeStyle.getLineCap();
61427 state.lineCap = strokeStyleLineCap !== undefined ?
61428 strokeStyleLineCap : ol.render.canvas.defaultLineCap;
61429 var strokeStyleLineDash = strokeStyle.getLineDash();
61430 state.lineDash = strokeStyleLineDash ?
61431 strokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
61432 var strokeStyleLineDashOffset = strokeStyle.getLineDashOffset();
61433 state.lineDashOffset = strokeStyleLineDashOffset ?
61434 strokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
61435 var strokeStyleLineJoin = strokeStyle.getLineJoin();
61436 state.lineJoin = strokeStyleLineJoin !== undefined ?
61437 strokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
61438 var strokeStyleWidth = strokeStyle.getWidth();
61439 state.lineWidth = strokeStyleWidth !== undefined ?
61440 strokeStyleWidth : ol.render.canvas.defaultLineWidth;
61441 var strokeStyleMiterLimit = strokeStyle.getMiterLimit();
61442 state.miterLimit = strokeStyleMiterLimit !== undefined ?
61443 strokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
61444
61445 if (state.lineWidth > this.maxLineWidth) {
61446 this.maxLineWidth = state.lineWidth;
61447 // invalidate the buffered max extent cache
61448 this.bufferedMaxExtent_ = null;
61449 }
61450 } else {
61451 state.strokeStyle = undefined;
61452 state.lineCap = undefined;
61453 state.lineDash = null;
61454 state.lineDashOffset = undefined;
61455 state.lineJoin = undefined;
61456 state.lineWidth = undefined;
61457 state.miterLimit = undefined;
61458 }
61459};
61460
61461
61462/**
61463 * @private
61464 * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
61465 */
61466ol.render.canvas.PolygonReplay.prototype.setFillStrokeStyles_ = function(geometry) {
61467 var state = this.state_;
61468 var fillStyle = state.fillStyle;
61469 var strokeStyle = state.strokeStyle;
61470 var lineCap = state.lineCap;
61471 var lineDash = state.lineDash;
61472 var lineDashOffset = state.lineDashOffset;
61473 var lineJoin = state.lineJoin;
61474 var lineWidth = state.lineWidth;
61475 var miterLimit = state.miterLimit;
61476 if (fillStyle !== undefined && (typeof fillStyle !== 'string' || state.currentFillStyle != fillStyle)) {
61477 var fillInstruction = [ol.render.canvas.Instruction.SET_FILL_STYLE, fillStyle];
61478 if (typeof fillStyle !== 'string') {
61479 var fillExtent = geometry.getExtent();
61480 fillInstruction.push([fillExtent[0], fillExtent[3]]);
61481 }
61482 this.instructions.push(fillInstruction);
61483 state.currentFillStyle = state.fillStyle;
61484 }
61485 if (strokeStyle !== undefined) {
61486 if (state.currentStrokeStyle != strokeStyle ||
61487 state.currentLineCap != lineCap ||
61488 !ol.array.equals(state.currentLineDash, lineDash) ||
61489 state.currentLineDashOffset != lineDashOffset ||
61490 state.currentLineJoin != lineJoin ||
61491 state.currentLineWidth != lineWidth ||
61492 state.currentMiterLimit != miterLimit) {
61493 this.instructions.push([
61494 ol.render.canvas.Instruction.SET_STROKE_STYLE,
61495 strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash, lineDashOffset, true, 1
61496 ]);
61497 state.currentStrokeStyle = strokeStyle;
61498 state.currentLineCap = lineCap;
61499 state.currentLineDash = lineDash;
61500 state.currentLineDashOffset = lineDashOffset;
61501 state.currentLineJoin = lineJoin;
61502 state.currentLineWidth = lineWidth;
61503 state.currentMiterLimit = miterLimit;
61504 }
61505 }
61506};
61507
61508goog.provide('ol.render.canvas.TextReplay');
61509
61510goog.require('ol');
61511goog.require('ol.colorlike');
61512goog.require('ol.render.canvas');
61513goog.require('ol.render.canvas.Instruction');
61514goog.require('ol.render.canvas.Replay');
61515
61516
61517/**
61518 * @constructor
61519 * @extends {ol.render.canvas.Replay}
61520 * @param {number} tolerance Tolerance.
61521 * @param {ol.Extent} maxExtent Maximum extent.
61522 * @param {number} resolution Resolution.
61523 * @param {boolean} overlaps The replay can have overlapping geometries.
61524 * @struct
61525 */
61526ol.render.canvas.TextReplay = function(tolerance, maxExtent, resolution, overlaps) {
61527
61528 ol.render.canvas.Replay.call(this, tolerance, maxExtent, resolution, overlaps);
61529
61530 /**
61531 * @private
61532 * @type {?ol.CanvasFillState}
61533 */
61534 this.replayFillState_ = null;
61535
61536 /**
61537 * @private
61538 * @type {?ol.CanvasStrokeState}
61539 */
61540 this.replayStrokeState_ = null;
61541
61542 /**
61543 * @private
61544 * @type {?ol.CanvasTextState}
61545 */
61546 this.replayTextState_ = null;
61547
61548 /**
61549 * @private
61550 * @type {string}
61551 */
61552 this.text_ = '';
61553
61554 /**
61555 * @private
61556 * @type {number}
61557 */
61558 this.textOffsetX_ = 0;
61559
61560 /**
61561 * @private
61562 * @type {number}
61563 */
61564 this.textOffsetY_ = 0;
61565
61566 /**
61567 * @private
61568 * @type {boolean|undefined}
61569 */
61570 this.textRotateWithView_ = undefined;
61571
61572 /**
61573 * @private
61574 * @type {number}
61575 */
61576 this.textRotation_ = 0;
61577
61578 /**
61579 * @private
61580 * @type {number}
61581 */
61582 this.textScale_ = 0;
61583
61584 /**
61585 * @private
61586 * @type {?ol.CanvasFillState}
61587 */
61588 this.textFillState_ = null;
61589
61590 /**
61591 * @private
61592 * @type {?ol.CanvasStrokeState}
61593 */
61594 this.textStrokeState_ = null;
61595
61596 /**
61597 * @private
61598 * @type {?ol.CanvasTextState}
61599 */
61600 this.textState_ = null;
61601
61602};
61603ol.inherits(ol.render.canvas.TextReplay, ol.render.canvas.Replay);
61604
61605
61606/**
61607 * @inheritDoc
61608 */
61609ol.render.canvas.TextReplay.prototype.drawText = function(flatCoordinates, offset, end, stride, geometry, feature) {
61610 if (this.text_ === '' || !this.textState_ ||
61611 (!this.textFillState_ && !this.textStrokeState_)) {
61612 return;
61613 }
61614 if (this.textFillState_) {
61615 this.setReplayFillState_(this.textFillState_);
61616 }
61617 if (this.textStrokeState_) {
61618 this.setReplayStrokeState_(this.textStrokeState_);
61619 }
61620 this.setReplayTextState_(this.textState_);
61621 this.beginGeometry(geometry, feature);
61622 var myBegin = this.coordinates.length;
61623 var myEnd =
61624 this.appendFlatCoordinates(flatCoordinates, offset, end, stride, false, false);
61625 var fill = !!this.textFillState_;
61626 var stroke = !!this.textStrokeState_;
61627 var drawTextInstruction = [
61628 ol.render.canvas.Instruction.DRAW_TEXT, myBegin, myEnd, this.text_,
61629 this.textOffsetX_, this.textOffsetY_, this.textRotation_, this.textScale_,
61630 fill, stroke, this.textRotateWithView_];
61631 this.instructions.push(drawTextInstruction);
61632 this.hitDetectionInstructions.push(drawTextInstruction);
61633 this.endGeometry(geometry, feature);
61634};
61635
61636
61637/**
61638 * @param {ol.CanvasFillState} fillState Fill state.
61639 * @private
61640 */
61641ol.render.canvas.TextReplay.prototype.setReplayFillState_ = function(fillState) {
61642 var replayFillState = this.replayFillState_;
61643 if (replayFillState &&
61644 replayFillState.fillStyle == fillState.fillStyle) {
61645 return;
61646 }
61647 var setFillStyleInstruction =
61648 [ol.render.canvas.Instruction.SET_FILL_STYLE, fillState.fillStyle];
61649 this.instructions.push(setFillStyleInstruction);
61650 this.hitDetectionInstructions.push(setFillStyleInstruction);
61651 if (!replayFillState) {
61652 this.replayFillState_ = {
61653 fillStyle: fillState.fillStyle
61654 };
61655 } else {
61656 replayFillState.fillStyle = fillState.fillStyle;
61657 }
61658};
61659
61660
61661/**
61662 * @param {ol.CanvasStrokeState} strokeState Stroke state.
61663 * @private
61664 */
61665ol.render.canvas.TextReplay.prototype.setReplayStrokeState_ = function(strokeState) {
61666 var replayStrokeState = this.replayStrokeState_;
61667 if (replayStrokeState &&
61668 replayStrokeState.lineCap == strokeState.lineCap &&
61669 replayStrokeState.lineDash == strokeState.lineDash &&
61670 replayStrokeState.lineDashOffset == strokeState.lineDashOffset &&
61671 replayStrokeState.lineJoin == strokeState.lineJoin &&
61672 replayStrokeState.lineWidth == strokeState.lineWidth &&
61673 replayStrokeState.miterLimit == strokeState.miterLimit &&
61674 replayStrokeState.strokeStyle == strokeState.strokeStyle) {
61675 return;
61676 }
61677 var setStrokeStyleInstruction = [
61678 ol.render.canvas.Instruction.SET_STROKE_STYLE, strokeState.strokeStyle,
61679 strokeState.lineWidth, strokeState.lineCap, strokeState.lineJoin,
61680 strokeState.miterLimit, strokeState.lineDash, strokeState.lineDashOffset, false, 1
61681 ];
61682 this.instructions.push(setStrokeStyleInstruction);
61683 this.hitDetectionInstructions.push(setStrokeStyleInstruction);
61684 if (!replayStrokeState) {
61685 this.replayStrokeState_ = {
61686 lineCap: strokeState.lineCap,
61687 lineDash: strokeState.lineDash,
61688 lineDashOffset: strokeState.lineDashOffset,
61689 lineJoin: strokeState.lineJoin,
61690 lineWidth: strokeState.lineWidth,
61691 miterLimit: strokeState.miterLimit,
61692 strokeStyle: strokeState.strokeStyle
61693 };
61694 } else {
61695 replayStrokeState.lineCap = strokeState.lineCap;
61696 replayStrokeState.lineDash = strokeState.lineDash;
61697 replayStrokeState.lineDashOffset = strokeState.lineDashOffset;
61698 replayStrokeState.lineJoin = strokeState.lineJoin;
61699 replayStrokeState.lineWidth = strokeState.lineWidth;
61700 replayStrokeState.miterLimit = strokeState.miterLimit;
61701 replayStrokeState.strokeStyle = strokeState.strokeStyle;
61702 }
61703};
61704
61705
61706/**
61707 * @param {ol.CanvasTextState} textState Text state.
61708 * @private
61709 */
61710ol.render.canvas.TextReplay.prototype.setReplayTextState_ = function(textState) {
61711 var replayTextState = this.replayTextState_;
61712 if (replayTextState &&
61713 replayTextState.font == textState.font &&
61714 replayTextState.textAlign == textState.textAlign &&
61715 replayTextState.textBaseline == textState.textBaseline) {
61716 return;
61717 }
61718 var setTextStyleInstruction = [ol.render.canvas.Instruction.SET_TEXT_STYLE,
61719 textState.font, textState.textAlign, textState.textBaseline];
61720 this.instructions.push(setTextStyleInstruction);
61721 this.hitDetectionInstructions.push(setTextStyleInstruction);
61722 if (!replayTextState) {
61723 this.replayTextState_ = {
61724 font: textState.font,
61725 textAlign: textState.textAlign,
61726 textBaseline: textState.textBaseline
61727 };
61728 } else {
61729 replayTextState.font = textState.font;
61730 replayTextState.textAlign = textState.textAlign;
61731 replayTextState.textBaseline = textState.textBaseline;
61732 }
61733};
61734
61735
61736/**
61737 * @inheritDoc
61738 */
61739ol.render.canvas.TextReplay.prototype.setTextStyle = function(textStyle) {
61740 if (!textStyle) {
61741 this.text_ = '';
61742 } else {
61743 var textFillStyle = textStyle.getFill();
61744 if (!textFillStyle) {
61745 this.textFillState_ = null;
61746 } else {
61747 var textFillStyleColor = textFillStyle.getColor();
61748 var fillStyle = ol.colorlike.asColorLike(textFillStyleColor ?
61749 textFillStyleColor : ol.render.canvas.defaultFillStyle);
61750 if (!this.textFillState_) {
61751 this.textFillState_ = {
61752 fillStyle: fillStyle
61753 };
61754 } else {
61755 var textFillState = this.textFillState_;
61756 textFillState.fillStyle = fillStyle;
61757 }
61758 }
61759 var textStrokeStyle = textStyle.getStroke();
61760 if (!textStrokeStyle) {
61761 this.textStrokeState_ = null;
61762 } else {
61763 var textStrokeStyleColor = textStrokeStyle.getColor();
61764 var textStrokeStyleLineCap = textStrokeStyle.getLineCap();
61765 var textStrokeStyleLineDash = textStrokeStyle.getLineDash();
61766 var textStrokeStyleLineDashOffset = textStrokeStyle.getLineDashOffset();
61767 var textStrokeStyleLineJoin = textStrokeStyle.getLineJoin();
61768 var textStrokeStyleWidth = textStrokeStyle.getWidth();
61769 var textStrokeStyleMiterLimit = textStrokeStyle.getMiterLimit();
61770 var lineCap = textStrokeStyleLineCap !== undefined ?
61771 textStrokeStyleLineCap : ol.render.canvas.defaultLineCap;
61772 var lineDash = textStrokeStyleLineDash ?
61773 textStrokeStyleLineDash.slice() : ol.render.canvas.defaultLineDash;
61774 var lineDashOffset = textStrokeStyleLineDashOffset !== undefined ?
61775 textStrokeStyleLineDashOffset : ol.render.canvas.defaultLineDashOffset;
61776 var lineJoin = textStrokeStyleLineJoin !== undefined ?
61777 textStrokeStyleLineJoin : ol.render.canvas.defaultLineJoin;
61778 var lineWidth = textStrokeStyleWidth !== undefined ?
61779 textStrokeStyleWidth : ol.render.canvas.defaultLineWidth;
61780 var miterLimit = textStrokeStyleMiterLimit !== undefined ?
61781 textStrokeStyleMiterLimit : ol.render.canvas.defaultMiterLimit;
61782 var strokeStyle = ol.colorlike.asColorLike(textStrokeStyleColor ?
61783 textStrokeStyleColor : ol.render.canvas.defaultStrokeStyle);
61784 if (!this.textStrokeState_) {
61785 this.textStrokeState_ = {
61786 lineCap: lineCap,
61787 lineDash: lineDash,
61788 lineDashOffset: lineDashOffset,
61789 lineJoin: lineJoin,
61790 lineWidth: lineWidth,
61791 miterLimit: miterLimit,
61792 strokeStyle: strokeStyle
61793 };
61794 } else {
61795 var textStrokeState = this.textStrokeState_;
61796 textStrokeState.lineCap = lineCap;
61797 textStrokeState.lineDash = lineDash;
61798 textStrokeState.lineDashOffset = lineDashOffset;
61799 textStrokeState.lineJoin = lineJoin;
61800 textStrokeState.lineWidth = lineWidth;
61801 textStrokeState.miterLimit = miterLimit;
61802 textStrokeState.strokeStyle = strokeStyle;
61803 }
61804 }
61805 var textFont = textStyle.getFont();
61806 var textOffsetX = textStyle.getOffsetX();
61807 var textOffsetY = textStyle.getOffsetY();
61808 var textRotateWithView = textStyle.getRotateWithView();
61809 var textRotation = textStyle.getRotation();
61810 var textScale = textStyle.getScale();
61811 var textText = textStyle.getText();
61812 var textTextAlign = textStyle.getTextAlign();
61813 var textTextBaseline = textStyle.getTextBaseline();
61814 var font = textFont !== undefined ?
61815 textFont : ol.render.canvas.defaultFont;
61816 var textAlign = textTextAlign !== undefined ?
61817 textTextAlign : ol.render.canvas.defaultTextAlign;
61818 var textBaseline = textTextBaseline !== undefined ?
61819 textTextBaseline : ol.render.canvas.defaultTextBaseline;
61820 if (!this.textState_) {
61821 this.textState_ = {
61822 font: font,
61823 textAlign: textAlign,
61824 textBaseline: textBaseline
61825 };
61826 } else {
61827 var textState = this.textState_;
61828 textState.font = font;
61829 textState.textAlign = textAlign;
61830 textState.textBaseline = textBaseline;
61831 }
61832 this.text_ = textText !== undefined ? textText : '';
61833 this.textOffsetX_ = textOffsetX !== undefined ? textOffsetX : 0;
61834 this.textOffsetY_ = textOffsetY !== undefined ? textOffsetY : 0;
61835 this.textRotateWithView_ = textRotateWithView !== undefined ? textRotateWithView : false;
61836 this.textRotation_ = textRotation !== undefined ? textRotation : 0;
61837 this.textScale_ = textScale !== undefined ? textScale : 1;
61838 }
61839};
61840
61841goog.provide('ol.render.canvas.ReplayGroup');
61842
61843goog.require('ol');
61844goog.require('ol.array');
61845goog.require('ol.dom');
61846goog.require('ol.extent');
61847goog.require('ol.geom.flat.transform');
61848goog.require('ol.obj');
61849goog.require('ol.render.ReplayGroup');
61850goog.require('ol.render.canvas.Replay');
61851goog.require('ol.render.canvas.ImageReplay');
61852goog.require('ol.render.canvas.LineStringReplay');
61853goog.require('ol.render.canvas.PolygonReplay');
61854goog.require('ol.render.canvas.TextReplay');
61855goog.require('ol.render.replay');
61856goog.require('ol.transform');
61857
61858
61859/**
61860 * @constructor
61861 * @extends {ol.render.ReplayGroup}
61862 * @param {number} tolerance Tolerance.
61863 * @param {ol.Extent} maxExtent Max extent.
61864 * @param {number} resolution Resolution.
61865 * @param {boolean} overlaps The replay group can have overlapping geometries.
61866 * @param {number=} opt_renderBuffer Optional rendering buffer.
61867 * @struct
61868 */
61869ol.render.canvas.ReplayGroup = function(
61870 tolerance, maxExtent, resolution, overlaps, opt_renderBuffer) {
61871 ol.render.ReplayGroup.call(this);
61872
61873 /**
61874 * @private
61875 * @type {number}
61876 */
61877 this.tolerance_ = tolerance;
61878
61879 /**
61880 * @private
61881 * @type {ol.Extent}
61882 */
61883 this.maxExtent_ = maxExtent;
61884
61885 /**
61886 * @private
61887 * @type {boolean}
61888 */
61889 this.overlaps_ = overlaps;
61890
61891 /**
61892 * @private
61893 * @type {number}
61894 */
61895 this.resolution_ = resolution;
61896
61897 /**
61898 * @private
61899 * @type {number|undefined}
61900 */
61901 this.renderBuffer_ = opt_renderBuffer;
61902
61903 /**
61904 * @private
61905 * @type {!Object.<string,
61906 * Object.<ol.render.ReplayType, ol.render.canvas.Replay>>}
61907 */
61908 this.replaysByZIndex_ = {};
61909
61910 /**
61911 * @private
61912 * @type {CanvasRenderingContext2D}
61913 */
61914 this.hitDetectionContext_ = ol.dom.createCanvasContext2D(1, 1);
61915
61916 /**
61917 * @private
61918 * @type {ol.Transform}
61919 */
61920 this.hitDetectionTransform_ = ol.transform.create();
61921};
61922ol.inherits(ol.render.canvas.ReplayGroup, ol.render.ReplayGroup);
61923
61924
61925/**
61926 * This cache is used for storing calculated pixel circles for increasing performance.
61927 * It is a static property to allow each Replaygroup to access it.
61928 * @type {Object.<number, Array.<Array.<(boolean|undefined)>>>}
61929 * @private
61930 */
61931ol.render.canvas.ReplayGroup.circleArrayCache_ = {
61932 0: [[true]]
61933};
61934
61935
61936/**
61937 * This method fills a row in the array from the given coordinate to the
61938 * middle with `true`.
61939 * @param {Array.<Array.<(boolean|undefined)>>} array The array that will be altered.
61940 * @param {number} x X coordinate.
61941 * @param {number} y Y coordinate.
61942 * @private
61943 */
61944ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_ = function(array, x, y) {
61945 var i;
61946 var radius = Math.floor(array.length / 2);
61947 if (x >= radius) {
61948 for (i = radius; i < x; i++) {
61949 array[i][y] = true;
61950 }
61951 } else if (x < radius) {
61952 for (i = x + 1; i < radius; i++) {
61953 array[i][y] = true;
61954 }
61955 }
61956};
61957
61958
61959/**
61960 * This methods creates a circle inside a fitting array. Points inside the
61961 * circle are marked by true, points on the outside are undefined.
61962 * It uses the midpoint circle algorithm.
61963 * A cache is used to increase performance.
61964 * @param {number} radius Radius.
61965 * @returns {Array.<Array.<(boolean|undefined)>>} An array with marked circle points.
61966 * @private
61967 */
61968ol.render.canvas.ReplayGroup.getCircleArray_ = function(radius) {
61969 if (ol.render.canvas.ReplayGroup.circleArrayCache_[radius] !== undefined) {
61970 return ol.render.canvas.ReplayGroup.circleArrayCache_[radius];
61971 }
61972
61973 var arraySize = radius * 2 + 1;
61974 var arr = new Array(arraySize);
61975 for (var i = 0; i < arraySize; i++) {
61976 arr[i] = new Array(arraySize);
61977 }
61978
61979 var x = radius;
61980 var y = 0;
61981 var error = 0;
61982
61983 while (x >= y) {
61984 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + x, radius + y);
61985 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + y, radius + x);
61986 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - y, radius + x);
61987 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - x, radius + y);
61988 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - x, radius - y);
61989 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius - y, radius - x);
61990 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + y, radius - x);
61991 ol.render.canvas.ReplayGroup.fillCircleArrayRowToMiddle_(arr, radius + x, radius - y);
61992
61993 y++;
61994 error += 1 + 2 * y;
61995 if (2 * (error - x) + 1 > 0) {
61996 x -= 1;
61997 error += 1 - 2 * x;
61998 }
61999 }
62000
62001 ol.render.canvas.ReplayGroup.circleArrayCache_[radius] = arr;
62002 return arr;
62003};
62004
62005
62006/**
62007 * @param {Array.<ol.render.ReplayType>} replays Replays.
62008 * @return {boolean} Has replays of the provided types.
62009 */
62010ol.render.canvas.ReplayGroup.prototype.hasReplays = function(replays) {
62011 for (var zIndex in this.replaysByZIndex_) {
62012 var candidates = this.replaysByZIndex_[zIndex];
62013 for (var i = 0, ii = replays.length; i < ii; ++i) {
62014 if (replays[i] in candidates) {
62015 return true;
62016 }
62017 }
62018 }
62019 return false;
62020};
62021
62022
62023/**
62024 * FIXME empty description for jsdoc
62025 */
62026ol.render.canvas.ReplayGroup.prototype.finish = function() {
62027 var zKey;
62028 for (zKey in this.replaysByZIndex_) {
62029 var replays = this.replaysByZIndex_[zKey];
62030 var replayKey;
62031 for (replayKey in replays) {
62032 replays[replayKey].finish();
62033 }
62034 }
62035};
62036
62037
62038/**
62039 * @param {ol.Coordinate} coordinate Coordinate.
62040 * @param {number} resolution Resolution.
62041 * @param {number} rotation Rotation.
62042 * @param {number} hitTolerance Hit tolerance in pixels.
62043 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
62044 * to skip.
62045 * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature
62046 * callback.
62047 * @return {T|undefined} Callback result.
62048 * @template T
62049 */
62050ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
62051 coordinate, resolution, rotation, hitTolerance, skippedFeaturesHash, callback) {
62052
62053 hitTolerance = Math.round(hitTolerance);
62054 var contextSize = hitTolerance * 2 + 1;
62055 var transform = ol.transform.compose(this.hitDetectionTransform_,
62056 hitTolerance + 0.5, hitTolerance + 0.5,
62057 1 / resolution, -1 / resolution,
62058 -rotation,
62059 -coordinate[0], -coordinate[1]);
62060 var context = this.hitDetectionContext_;
62061
62062 if (context.canvas.width !== contextSize || context.canvas.height !== contextSize) {
62063 context.canvas.width = contextSize;
62064 context.canvas.height = contextSize;
62065 } else {
62066 context.clearRect(0, 0, contextSize, contextSize);
62067 }
62068
62069 /**
62070 * @type {ol.Extent}
62071 */
62072 var hitExtent;
62073 if (this.renderBuffer_ !== undefined) {
62074 hitExtent = ol.extent.createEmpty();
62075 ol.extent.extendCoordinate(hitExtent, coordinate);
62076 ol.extent.buffer(hitExtent, resolution * (this.renderBuffer_ + hitTolerance), hitExtent);
62077 }
62078
62079 var mask = ol.render.canvas.ReplayGroup.getCircleArray_(hitTolerance);
62080
62081 return this.replayHitDetection_(context, transform, rotation,
62082 skippedFeaturesHash,
62083 /**
62084 * @param {ol.Feature|ol.render.Feature} feature Feature.
62085 * @return {?} Callback result.
62086 */
62087 function(feature) {
62088 var imageData = context.getImageData(0, 0, contextSize, contextSize).data;
62089 for (var i = 0; i < contextSize; i++) {
62090 for (var j = 0; j < contextSize; j++) {
62091 if (mask[i][j]) {
62092 if (imageData[(j * contextSize + i) * 4 + 3] > 0) {
62093 var result = callback(feature);
62094 if (result) {
62095 return result;
62096 } else {
62097 context.clearRect(0, 0, contextSize, contextSize);
62098 return undefined;
62099 }
62100 }
62101 }
62102 }
62103 }
62104 }, hitExtent);
62105};
62106
62107
62108/**
62109 * @param {ol.Transform} transform Transform.
62110 * @return {Array.<number>} Clip coordinates.
62111 */
62112ol.render.canvas.ReplayGroup.prototype.getClipCoords = function(transform) {
62113 var maxExtent = this.maxExtent_;
62114 var minX = maxExtent[0];
62115 var minY = maxExtent[1];
62116 var maxX = maxExtent[2];
62117 var maxY = maxExtent[3];
62118 var flatClipCoords = [minX, minY, minX, maxY, maxX, maxY, maxX, minY];
62119 ol.geom.flat.transform.transform2D(
62120 flatClipCoords, 0, 8, 2, transform, flatClipCoords);
62121 return flatClipCoords;
62122};
62123
62124
62125/**
62126 * @inheritDoc
62127 */
62128ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
62129 var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
62130 var replays = this.replaysByZIndex_[zIndexKey];
62131 if (replays === undefined) {
62132 replays = {};
62133 this.replaysByZIndex_[zIndexKey] = replays;
62134 }
62135 var replay = replays[replayType];
62136 if (replay === undefined) {
62137 var Constructor = ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
62138 replay = new Constructor(this.tolerance_, this.maxExtent_,
62139 this.resolution_, this.overlaps_);
62140 replays[replayType] = replay;
62141 }
62142 return replay;
62143};
62144
62145
62146/**
62147 * @inheritDoc
62148 */
62149ol.render.canvas.ReplayGroup.prototype.isEmpty = function() {
62150 return ol.obj.isEmpty(this.replaysByZIndex_);
62151};
62152
62153
62154/**
62155 * @param {CanvasRenderingContext2D} context Context.
62156 * @param {number} pixelRatio Pixel ratio.
62157 * @param {ol.Transform} transform Transform.
62158 * @param {number} viewRotation View rotation.
62159 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
62160 * to skip.
62161 * @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types
62162 * to replay. Default is {@link ol.render.replay.ORDER}
62163 */
62164ol.render.canvas.ReplayGroup.prototype.replay = function(context, pixelRatio,
62165 transform, viewRotation, skippedFeaturesHash, opt_replayTypes) {
62166
62167 /** @type {Array.<number>} */
62168 var zs = Object.keys(this.replaysByZIndex_).map(Number);
62169 zs.sort(ol.array.numberSafeCompareFunction);
62170
62171 // setup clipping so that the parts of over-simplified geometries are not
62172 // visible outside the current extent when panning
62173 var flatClipCoords = this.getClipCoords(transform);
62174 context.save();
62175 context.beginPath();
62176 context.moveTo(flatClipCoords[0], flatClipCoords[1]);
62177 context.lineTo(flatClipCoords[2], flatClipCoords[3]);
62178 context.lineTo(flatClipCoords[4], flatClipCoords[5]);
62179 context.lineTo(flatClipCoords[6], flatClipCoords[7]);
62180 context.clip();
62181
62182 var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER;
62183 var i, ii, j, jj, replays, replay;
62184 for (i = 0, ii = zs.length; i < ii; ++i) {
62185 replays = this.replaysByZIndex_[zs[i].toString()];
62186 for (j = 0, jj = replayTypes.length; j < jj; ++j) {
62187 replay = replays[replayTypes[j]];
62188 if (replay !== undefined) {
62189 replay.replay(context, pixelRatio, transform, viewRotation,
62190 skippedFeaturesHash);
62191 }
62192 }
62193 }
62194
62195 context.restore();
62196};
62197
62198
62199/**
62200 * @private
62201 * @param {CanvasRenderingContext2D} context Context.
62202 * @param {ol.Transform} transform Transform.
62203 * @param {number} viewRotation View rotation.
62204 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
62205 * to skip.
62206 * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback
62207 * Feature callback.
62208 * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
62209 * extent.
62210 * @return {T|undefined} Callback result.
62211 * @template T
62212 */
62213ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
62214 context, transform, viewRotation, skippedFeaturesHash,
62215 featureCallback, opt_hitExtent) {
62216 /** @type {Array.<number>} */
62217 var zs = Object.keys(this.replaysByZIndex_).map(Number);
62218 zs.sort(function(a, b) {
62219 return b - a;
62220 });
62221
62222 var i, ii, j, replays, replay, result;
62223 for (i = 0, ii = zs.length; i < ii; ++i) {
62224 replays = this.replaysByZIndex_[zs[i].toString()];
62225 for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
62226 replay = replays[ol.render.replay.ORDER[j]];
62227 if (replay !== undefined) {
62228 result = replay.replayHitDetection(context, transform, viewRotation,
62229 skippedFeaturesHash, featureCallback, opt_hitExtent);
62230 if (result) {
62231 return result;
62232 }
62233 }
62234 }
62235 }
62236 return undefined;
62237};
62238
62239
62240/**
62241 * @const
62242 * @private
62243 * @type {Object.<ol.render.ReplayType,
62244 * function(new: ol.render.canvas.Replay, number, ol.Extent,
62245 * number, boolean)>}
62246 */
62247ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = {
62248 'Circle': ol.render.canvas.PolygonReplay,
62249 'Default': ol.render.canvas.Replay,
62250 'Image': ol.render.canvas.ImageReplay,
62251 'LineString': ol.render.canvas.LineStringReplay,
62252 'Polygon': ol.render.canvas.PolygonReplay,
62253 'Text': ol.render.canvas.TextReplay
62254};
62255
62256goog.provide('ol.renderer.Layer');
62257
62258goog.require('ol');
62259goog.require('ol.ImageState');
62260goog.require('ol.Observable');
62261goog.require('ol.TileState');
62262goog.require('ol.asserts');
62263goog.require('ol.events');
62264goog.require('ol.events.EventType');
62265goog.require('ol.functions');
62266goog.require('ol.source.State');
62267
62268
62269/**
62270 * @constructor
62271 * @extends {ol.Observable}
62272 * @param {ol.layer.Layer} layer Layer.
62273 * @struct
62274 */
62275ol.renderer.Layer = function(layer) {
62276
62277 ol.Observable.call(this);
62278
62279 /**
62280 * @private
62281 * @type {ol.layer.Layer}
62282 */
62283 this.layer_ = layer;
62284
62285
62286};
62287ol.inherits(ol.renderer.Layer, ol.Observable);
62288
62289
62290/**
62291 * @param {ol.Coordinate} coordinate Coordinate.
62292 * @param {olx.FrameState} frameState Frame state.
62293 * @param {number} hitTolerance Hit tolerance in pixels.
62294 * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T}
62295 * callback Feature callback.
62296 * @param {S} thisArg Value to use as `this` when executing `callback`.
62297 * @return {T|undefined} Callback result.
62298 * @template S,T
62299 */
62300ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = ol.nullFunction;
62301
62302
62303/**
62304 * @param {ol.Coordinate} coordinate Coordinate.
62305 * @param {olx.FrameState} frameState Frame state.
62306 * @return {boolean} Is there a feature at the given coordinate?
62307 */
62308ol.renderer.Layer.prototype.hasFeatureAtCoordinate = ol.functions.FALSE;
62309
62310
62311/**
62312 * Create a function that adds loaded tiles to the tile lookup.
62313 * @param {ol.source.Tile} source Tile source.
62314 * @param {ol.proj.Projection} projection Projection of the tiles.
62315 * @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded
62316 * tiles by zoom level.
62317 * @return {function(number, ol.TileRange):boolean} A function that can be
62318 * called with a zoom level and a tile range to add loaded tiles to the
62319 * lookup.
62320 * @protected
62321 */
62322ol.renderer.Layer.prototype.createLoadedTileFinder = function(source, projection, tiles) {
62323 return (
62324 /**
62325 * @param {number} zoom Zoom level.
62326 * @param {ol.TileRange} tileRange Tile range.
62327 * @return {boolean} The tile range is fully loaded.
62328 */
62329 function(zoom, tileRange) {
62330 function callback(tile) {
62331 if (!tiles[zoom]) {
62332 tiles[zoom] = {};
62333 }
62334 tiles[zoom][tile.tileCoord.toString()] = tile;
62335 }
62336 return source.forEachLoadedTile(projection, zoom, tileRange, callback);
62337 });
62338};
62339
62340
62341/**
62342 * @return {ol.layer.Layer} Layer.
62343 */
62344ol.renderer.Layer.prototype.getLayer = function() {
62345 return this.layer_;
62346};
62347
62348
62349/**
62350 * Handle changes in image state.
62351 * @param {ol.events.Event} event Image change event.
62352 * @private
62353 */
62354ol.renderer.Layer.prototype.handleImageChange_ = function(event) {
62355 var image = /** @type {ol.Image} */ (event.target);
62356 if (image.getState() === ol.ImageState.LOADED) {
62357 this.renderIfReadyAndVisible();
62358 }
62359};
62360
62361
62362/**
62363 * Load the image if not already loaded, and register the image change
62364 * listener if needed.
62365 * @param {ol.ImageBase} image Image.
62366 * @return {boolean} `true` if the image is already loaded, `false`
62367 * otherwise.
62368 * @protected
62369 */
62370ol.renderer.Layer.prototype.loadImage = function(image) {
62371 var imageState = image.getState();
62372 if (imageState != ol.ImageState.LOADED &&
62373 imageState != ol.ImageState.ERROR) {
62374 ol.events.listen(image, ol.events.EventType.CHANGE,
62375 this.handleImageChange_, this);
62376 }
62377 if (imageState == ol.ImageState.IDLE) {
62378 image.load();
62379 imageState = image.getState();
62380 }
62381 return imageState == ol.ImageState.LOADED;
62382};
62383
62384
62385/**
62386 * @protected
62387 */
62388ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() {
62389 var layer = this.getLayer();
62390 if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) {
62391 this.changed();
62392 }
62393};
62394
62395
62396/**
62397 * @param {olx.FrameState} frameState Frame state.
62398 * @param {ol.source.Tile} tileSource Tile source.
62399 * @protected
62400 */
62401ol.renderer.Layer.prototype.scheduleExpireCache = function(frameState, tileSource) {
62402 if (tileSource.canExpireCache()) {
62403 /**
62404 * @param {ol.source.Tile} tileSource Tile source.
62405 * @param {ol.Map} map Map.
62406 * @param {olx.FrameState} frameState Frame state.
62407 */
62408 var postRenderFunction = function(tileSource, map, frameState) {
62409 var tileSourceKey = ol.getUid(tileSource).toString();
62410 if (tileSourceKey in frameState.usedTiles) {
62411 tileSource.expireCache(frameState.viewState.projection,
62412 frameState.usedTiles[tileSourceKey]);
62413 }
62414 }.bind(null, tileSource);
62415
62416 frameState.postRenderFunctions.push(
62417 /** @type {ol.PostRenderFunction} */ (postRenderFunction)
62418 );
62419 }
62420};
62421
62422
62423/**
62424 * @param {Object.<string, ol.Attribution>} attributionsSet Attributions
62425 * set (target).
62426 * @param {Array.<ol.Attribution>} attributions Attributions (source).
62427 * @protected
62428 */
62429ol.renderer.Layer.prototype.updateAttributions = function(attributionsSet, attributions) {
62430 if (attributions) {
62431 var attribution, i, ii;
62432 for (i = 0, ii = attributions.length; i < ii; ++i) {
62433 attribution = attributions[i];
62434 attributionsSet[ol.getUid(attribution).toString()] = attribution;
62435 }
62436 }
62437};
62438
62439
62440/**
62441 * @param {olx.FrameState} frameState Frame state.
62442 * @param {ol.source.Source} source Source.
62443 * @protected
62444 */
62445ol.renderer.Layer.prototype.updateLogos = function(frameState, source) {
62446 var logo = source.getLogo();
62447 if (logo !== undefined) {
62448 if (typeof logo === 'string') {
62449 frameState.logos[logo] = '';
62450 } else if (logo) {
62451 ol.asserts.assert(typeof logo.href == 'string', 44); // `logo.href` should be a string.
62452 ol.asserts.assert(typeof logo.src == 'string', 45); // `logo.src` should be a string.
62453 frameState.logos[logo.src] = logo.href;
62454 }
62455 }
62456};
62457
62458
62459/**
62460 * @param {Object.<string, Object.<string, ol.TileRange>>} usedTiles Used tiles.
62461 * @param {ol.source.Tile} tileSource Tile source.
62462 * @param {number} z Z.
62463 * @param {ol.TileRange} tileRange Tile range.
62464 * @protected
62465 */
62466ol.renderer.Layer.prototype.updateUsedTiles = function(usedTiles, tileSource, z, tileRange) {
62467 // FIXME should we use tilesToDrawByZ instead?
62468 var tileSourceKey = ol.getUid(tileSource).toString();
62469 var zKey = z.toString();
62470 if (tileSourceKey in usedTiles) {
62471 if (zKey in usedTiles[tileSourceKey]) {
62472 usedTiles[tileSourceKey][zKey].extend(tileRange);
62473 } else {
62474 usedTiles[tileSourceKey][zKey] = tileRange;
62475 }
62476 } else {
62477 usedTiles[tileSourceKey] = {};
62478 usedTiles[tileSourceKey][zKey] = tileRange;
62479 }
62480};
62481
62482
62483/**
62484 * Manage tile pyramid.
62485 * This function performs a number of functions related to the tiles at the
62486 * current zoom and lower zoom levels:
62487 * - registers idle tiles in frameState.wantedTiles so that they are not
62488 * discarded by the tile queue
62489 * - enqueues missing tiles
62490 * @param {olx.FrameState} frameState Frame state.
62491 * @param {ol.source.Tile} tileSource Tile source.
62492 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
62493 * @param {number} pixelRatio Pixel ratio.
62494 * @param {ol.proj.Projection} projection Projection.
62495 * @param {ol.Extent} extent Extent.
62496 * @param {number} currentZ Current Z.
62497 * @param {number} preload Load low resolution tiles up to 'preload' levels.
62498 * @param {function(this: T, ol.Tile)=} opt_tileCallback Tile callback.
62499 * @param {T=} opt_this Object to use as `this` in `opt_tileCallback`.
62500 * @protected
62501 * @template T
62502 */
62503ol.renderer.Layer.prototype.manageTilePyramid = function(
62504 frameState, tileSource, tileGrid, pixelRatio, projection, extent,
62505 currentZ, preload, opt_tileCallback, opt_this) {
62506 var tileSourceKey = ol.getUid(tileSource).toString();
62507 if (!(tileSourceKey in frameState.wantedTiles)) {
62508 frameState.wantedTiles[tileSourceKey] = {};
62509 }
62510 var wantedTiles = frameState.wantedTiles[tileSourceKey];
62511 var tileQueue = frameState.tileQueue;
62512 var minZoom = tileGrid.getMinZoom();
62513 var tile, tileRange, tileResolution, x, y, z;
62514 for (z = currentZ; z >= minZoom; --z) {
62515 tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z, tileRange);
62516 tileResolution = tileGrid.getResolution(z);
62517 for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
62518 for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
62519 if (currentZ - z <= preload) {
62520 tile = tileSource.getTile(z, x, y, pixelRatio, projection);
62521 if (tile.getState() == ol.TileState.IDLE) {
62522 wantedTiles[tile.getKey()] = true;
62523 if (!tileQueue.isKeyQueued(tile.getKey())) {
62524 tileQueue.enqueue([tile, tileSourceKey,
62525 tileGrid.getTileCoordCenter(tile.tileCoord), tileResolution]);
62526 }
62527 }
62528 if (opt_tileCallback !== undefined) {
62529 opt_tileCallback.call(opt_this, tile);
62530 }
62531 } else {
62532 tileSource.useTile(z, x, y, projection);
62533 }
62534 }
62535 }
62536 }
62537};
62538
62539goog.provide('ol.renderer.canvas.Layer');
62540
62541goog.require('ol');
62542goog.require('ol.extent');
62543goog.require('ol.functions');
62544goog.require('ol.render.Event');
62545goog.require('ol.render.EventType');
62546goog.require('ol.render.canvas');
62547goog.require('ol.render.canvas.Immediate');
62548goog.require('ol.renderer.Layer');
62549goog.require('ol.transform');
62550
62551
62552/**
62553 * @constructor
62554 * @abstract
62555 * @extends {ol.renderer.Layer}
62556 * @param {ol.layer.Layer} layer Layer.
62557 */
62558ol.renderer.canvas.Layer = function(layer) {
62559
62560 ol.renderer.Layer.call(this, layer);
62561
62562 /**
62563 * @protected
62564 * @type {number}
62565 */
62566 this.renderedResolution;
62567
62568 /**
62569 * @private
62570 * @type {ol.Transform}
62571 */
62572 this.transform_ = ol.transform.create();
62573
62574};
62575ol.inherits(ol.renderer.canvas.Layer, ol.renderer.Layer);
62576
62577
62578/**
62579 * @param {CanvasRenderingContext2D} context Context.
62580 * @param {olx.FrameState} frameState Frame state.
62581 * @param {ol.Extent} extent Clip extent.
62582 * @protected
62583 */
62584ol.renderer.canvas.Layer.prototype.clip = function(context, frameState, extent) {
62585 var pixelRatio = frameState.pixelRatio;
62586 var width = frameState.size[0] * pixelRatio;
62587 var height = frameState.size[1] * pixelRatio;
62588 var rotation = frameState.viewState.rotation;
62589 var topLeft = ol.extent.getTopLeft(/** @type {ol.Extent} */ (extent));
62590 var topRight = ol.extent.getTopRight(/** @type {ol.Extent} */ (extent));
62591 var bottomRight = ol.extent.getBottomRight(/** @type {ol.Extent} */ (extent));
62592 var bottomLeft = ol.extent.getBottomLeft(/** @type {ol.Extent} */ (extent));
62593
62594 ol.transform.apply(frameState.coordinateToPixelTransform, topLeft);
62595 ol.transform.apply(frameState.coordinateToPixelTransform, topRight);
62596 ol.transform.apply(frameState.coordinateToPixelTransform, bottomRight);
62597 ol.transform.apply(frameState.coordinateToPixelTransform, bottomLeft);
62598
62599 context.save();
62600 ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
62601 context.beginPath();
62602 context.moveTo(topLeft[0] * pixelRatio, topLeft[1] * pixelRatio);
62603 context.lineTo(topRight[0] * pixelRatio, topRight[1] * pixelRatio);
62604 context.lineTo(bottomRight[0] * pixelRatio, bottomRight[1] * pixelRatio);
62605 context.lineTo(bottomLeft[0] * pixelRatio, bottomLeft[1] * pixelRatio);
62606 context.clip();
62607 ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
62608};
62609
62610
62611/**
62612 * @param {ol.render.EventType} type Event type.
62613 * @param {CanvasRenderingContext2D} context Context.
62614 * @param {olx.FrameState} frameState Frame state.
62615 * @param {ol.Transform=} opt_transform Transform.
62616 * @private
62617 */
62618ol.renderer.canvas.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState, opt_transform) {
62619 var layer = this.getLayer();
62620 if (layer.hasListener(type)) {
62621 var width = frameState.size[0] * frameState.pixelRatio;
62622 var height = frameState.size[1] * frameState.pixelRatio;
62623 var rotation = frameState.viewState.rotation;
62624 ol.render.canvas.rotateAtOffset(context, -rotation, width / 2, height / 2);
62625 var transform = opt_transform !== undefined ?
62626 opt_transform : this.getTransform(frameState, 0);
62627 var render = new ol.render.canvas.Immediate(
62628 context, frameState.pixelRatio, frameState.extent, transform,
62629 frameState.viewState.rotation);
62630 var composeEvent = new ol.render.Event(type, render, frameState,
62631 context, null);
62632 layer.dispatchEvent(composeEvent);
62633 ol.render.canvas.rotateAtOffset(context, rotation, width / 2, height / 2);
62634 }
62635};
62636
62637
62638/**
62639 * @param {ol.Coordinate} coordinate Coordinate.
62640 * @param {olx.FrameState} frameState FrameState.
62641 * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
62642 * callback.
62643 * @param {S} thisArg Value to use as `this` when executing `callback`.
62644 * @return {T|undefined} Callback result.
62645 * @template S,T,U
62646 */
62647ol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {
62648 var hasFeature = this.forEachFeatureAtCoordinate(
62649 coordinate, frameState, 0, ol.functions.TRUE, this);
62650
62651 if (hasFeature) {
62652 return callback.call(thisArg, this.getLayer(), null);
62653 } else {
62654 return undefined;
62655 }
62656};
62657
62658
62659/**
62660 * @param {CanvasRenderingContext2D} context Context.
62661 * @param {olx.FrameState} frameState Frame state.
62662 * @param {ol.LayerState} layerState Layer state.
62663 * @param {ol.Transform=} opt_transform Transform.
62664 * @protected
62665 */
62666ol.renderer.canvas.Layer.prototype.postCompose = function(context, frameState, layerState, opt_transform) {
62667 this.dispatchComposeEvent_(ol.render.EventType.POSTCOMPOSE, context,
62668 frameState, opt_transform);
62669};
62670
62671
62672/**
62673 * @param {CanvasRenderingContext2D} context Context.
62674 * @param {olx.FrameState} frameState Frame state.
62675 * @param {ol.Transform=} opt_transform Transform.
62676 * @protected
62677 */
62678ol.renderer.canvas.Layer.prototype.preCompose = function(context, frameState, opt_transform) {
62679 this.dispatchComposeEvent_(ol.render.EventType.PRECOMPOSE, context,
62680 frameState, opt_transform);
62681};
62682
62683
62684/**
62685 * @param {CanvasRenderingContext2D} context Context.
62686 * @param {olx.FrameState} frameState Frame state.
62687 * @param {ol.Transform=} opt_transform Transform.
62688 * @protected
62689 */
62690ol.renderer.canvas.Layer.prototype.dispatchRenderEvent = function(context, frameState, opt_transform) {
62691 this.dispatchComposeEvent_(ol.render.EventType.RENDER, context,
62692 frameState, opt_transform);
62693};
62694
62695
62696/**
62697 * @param {olx.FrameState} frameState Frame state.
62698 * @param {number} offsetX Offset on the x-axis in view coordinates.
62699 * @protected
62700 * @return {!ol.Transform} Transform.
62701 */
62702ol.renderer.canvas.Layer.prototype.getTransform = function(frameState, offsetX) {
62703 var viewState = frameState.viewState;
62704 var pixelRatio = frameState.pixelRatio;
62705 var dx1 = pixelRatio * frameState.size[0] / 2;
62706 var dy1 = pixelRatio * frameState.size[1] / 2;
62707 var sx = pixelRatio / viewState.resolution;
62708 var sy = -sx;
62709 var angle = -viewState.rotation;
62710 var dx2 = -viewState.center[0] + offsetX;
62711 var dy2 = -viewState.center[1];
62712 return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, angle, dx2, dy2);
62713};
62714
62715
62716/**
62717 * @abstract
62718 * @param {olx.FrameState} frameState Frame state.
62719 * @param {ol.LayerState} layerState Layer state.
62720 * @param {CanvasRenderingContext2D} context Context.
62721 */
62722ol.renderer.canvas.Layer.prototype.composeFrame = function(frameState, layerState, context) {};
62723
62724/**
62725 * @abstract
62726 * @param {olx.FrameState} frameState Frame state.
62727 * @param {ol.LayerState} layerState Layer state.
62728 * @return {boolean} whether composeFrame should be called.
62729 */
62730ol.renderer.canvas.Layer.prototype.prepareFrame = function(frameState, layerState) {};
62731
62732goog.provide('ol.renderer.vector');
62733
62734goog.require('ol');
62735goog.require('ol.ImageState');
62736goog.require('ol.geom.GeometryType');
62737goog.require('ol.render.ReplayType');
62738
62739
62740/**
62741 * @param {ol.Feature|ol.render.Feature} feature1 Feature 1.
62742 * @param {ol.Feature|ol.render.Feature} feature2 Feature 2.
62743 * @return {number} Order.
62744 */
62745ol.renderer.vector.defaultOrder = function(feature1, feature2) {
62746 return ol.getUid(feature1) - ol.getUid(feature2);
62747};
62748
62749
62750/**
62751 * @param {number} resolution Resolution.
62752 * @param {number} pixelRatio Pixel ratio.
62753 * @return {number} Squared pixel tolerance.
62754 */
62755ol.renderer.vector.getSquaredTolerance = function(resolution, pixelRatio) {
62756 var tolerance = ol.renderer.vector.getTolerance(resolution, pixelRatio);
62757 return tolerance * tolerance;
62758};
62759
62760
62761/**
62762 * @param {number} resolution Resolution.
62763 * @param {number} pixelRatio Pixel ratio.
62764 * @return {number} Pixel tolerance.
62765 */
62766ol.renderer.vector.getTolerance = function(resolution, pixelRatio) {
62767 return ol.SIMPLIFY_TOLERANCE * resolution / pixelRatio;
62768};
62769
62770
62771/**
62772 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62773 * @param {ol.geom.Circle} geometry Geometry.
62774 * @param {ol.style.Style} style Style.
62775 * @param {ol.Feature} feature Feature.
62776 * @private
62777 */
62778ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style, feature) {
62779 var fillStyle = style.getFill();
62780 var strokeStyle = style.getStroke();
62781 if (fillStyle || strokeStyle) {
62782 var circleReplay = replayGroup.getReplay(
62783 style.getZIndex(), ol.render.ReplayType.CIRCLE);
62784 circleReplay.setFillStrokeStyle(fillStyle, strokeStyle);
62785 circleReplay.drawCircle(geometry, feature);
62786 }
62787 var textStyle = style.getText();
62788 if (textStyle) {
62789 var textReplay = replayGroup.getReplay(
62790 style.getZIndex(), ol.render.ReplayType.TEXT);
62791 textReplay.setTextStyle(textStyle);
62792 textReplay.drawText(geometry.getCenter(), 0, 2, 2, geometry, feature);
62793 }
62794};
62795
62796
62797/**
62798 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62799 * @param {ol.Feature|ol.render.Feature} feature Feature.
62800 * @param {ol.style.Style} style Style.
62801 * @param {number} squaredTolerance Squared tolerance.
62802 * @param {function(this: T, ol.events.Event)} listener Listener function.
62803 * @param {T} thisArg Value to use as `this` when executing `listener`.
62804 * @return {boolean} `true` if style is loading.
62805 * @template T
62806 */
62807ol.renderer.vector.renderFeature = function(
62808 replayGroup, feature, style, squaredTolerance, listener, thisArg) {
62809 var loading = false;
62810 var imageStyle, imageState;
62811 imageStyle = style.getImage();
62812 if (imageStyle) {
62813 imageState = imageStyle.getImageState();
62814 if (imageState == ol.ImageState.LOADED ||
62815 imageState == ol.ImageState.ERROR) {
62816 imageStyle.unlistenImageChange(listener, thisArg);
62817 } else {
62818 if (imageState == ol.ImageState.IDLE) {
62819 imageStyle.load();
62820 }
62821 imageState = imageStyle.getImageState();
62822 imageStyle.listenImageChange(listener, thisArg);
62823 loading = true;
62824 }
62825 }
62826 ol.renderer.vector.renderFeature_(replayGroup, feature, style,
62827 squaredTolerance);
62828 return loading;
62829};
62830
62831
62832/**
62833 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62834 * @param {ol.Feature|ol.render.Feature} feature Feature.
62835 * @param {ol.style.Style} style Style.
62836 * @param {number} squaredTolerance Squared tolerance.
62837 * @private
62838 */
62839ol.renderer.vector.renderFeature_ = function(
62840 replayGroup, feature, style, squaredTolerance) {
62841 var geometry = style.getGeometryFunction()(feature);
62842 if (!geometry) {
62843 return;
62844 }
62845 var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
62846 var renderer = style.getRenderer();
62847 if (renderer) {
62848 ol.renderer.vector.renderGeometry_(replayGroup, simplifiedGeometry, style, feature);
62849 } else {
62850 var geometryRenderer =
62851 ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()];
62852 geometryRenderer(replayGroup, simplifiedGeometry, style, feature);
62853 }
62854};
62855
62856
62857/**
62858 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62859 * @param {ol.geom.Geometry} geometry Geometry.
62860 * @param {ol.style.Style} style Style.
62861 * @param {ol.Feature|ol.render.Feature} feature Feature.
62862 * @private
62863 */
62864ol.renderer.vector.renderGeometry_ = function(replayGroup, geometry, style, feature) {
62865 if (geometry.getType() == ol.geom.GeometryType.GEOMETRY_COLLECTION) {
62866 var geometries = /** @type {ol.geom.GeometryCollection} */ (geometry).getGeometries();
62867 for (var i = 0, ii = geometries.length; i < ii; ++i) {
62868 ol.renderer.vector.renderGeometry_(replayGroup, geometries[i], style, feature);
62869 }
62870 return;
62871 }
62872 var replay = replayGroup.getReplay(style.getZIndex(), ol.render.ReplayType.DEFAULT);
62873 replay.drawCustom(/** @type {ol.geom.SimpleGeometry} */ (geometry), feature, style.getRenderer());
62874};
62875
62876
62877/**
62878 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62879 * @param {ol.geom.GeometryCollection} geometry Geometry.
62880 * @param {ol.style.Style} style Style.
62881 * @param {ol.Feature} feature Feature.
62882 * @private
62883 */
62884ol.renderer.vector.renderGeometryCollectionGeometry_ = function(replayGroup, geometry, style, feature) {
62885 var geometries = geometry.getGeometriesArray();
62886 var i, ii;
62887 for (i = 0, ii = geometries.length; i < ii; ++i) {
62888 var geometryRenderer =
62889 ol.renderer.vector.GEOMETRY_RENDERERS_[geometries[i].getType()];
62890 geometryRenderer(replayGroup, geometries[i], style, feature);
62891 }
62892};
62893
62894
62895/**
62896 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62897 * @param {ol.geom.LineString|ol.render.Feature} geometry Geometry.
62898 * @param {ol.style.Style} style Style.
62899 * @param {ol.Feature|ol.render.Feature} feature Feature.
62900 * @private
62901 */
62902ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, style, feature) {
62903 var strokeStyle = style.getStroke();
62904 if (strokeStyle) {
62905 var lineStringReplay = replayGroup.getReplay(
62906 style.getZIndex(), ol.render.ReplayType.LINE_STRING);
62907 lineStringReplay.setFillStrokeStyle(null, strokeStyle);
62908 lineStringReplay.drawLineString(geometry, feature);
62909 }
62910 var textStyle = style.getText();
62911 if (textStyle) {
62912 var textReplay = replayGroup.getReplay(
62913 style.getZIndex(), ol.render.ReplayType.TEXT);
62914 textReplay.setTextStyle(textStyle);
62915 textReplay.drawText(geometry.getFlatMidpoint(), 0, 2, 2, geometry, feature);
62916 }
62917};
62918
62919
62920/**
62921 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62922 * @param {ol.geom.MultiLineString|ol.render.Feature} geometry Geometry.
62923 * @param {ol.style.Style} style Style.
62924 * @param {ol.Feature|ol.render.Feature} feature Feature.
62925 * @private
62926 */
62927ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geometry, style, feature) {
62928 var strokeStyle = style.getStroke();
62929 if (strokeStyle) {
62930 var lineStringReplay = replayGroup.getReplay(
62931 style.getZIndex(), ol.render.ReplayType.LINE_STRING);
62932 lineStringReplay.setFillStrokeStyle(null, strokeStyle);
62933 lineStringReplay.drawMultiLineString(geometry, feature);
62934 }
62935 var textStyle = style.getText();
62936 if (textStyle) {
62937 var textReplay = replayGroup.getReplay(
62938 style.getZIndex(), ol.render.ReplayType.TEXT);
62939 textReplay.setTextStyle(textStyle);
62940 var flatMidpointCoordinates = geometry.getFlatMidpoints();
62941 textReplay.drawText(flatMidpointCoordinates, 0,
62942 flatMidpointCoordinates.length, 2, geometry, feature);
62943 }
62944};
62945
62946
62947/**
62948 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62949 * @param {ol.geom.MultiPolygon} geometry Geometry.
62950 * @param {ol.style.Style} style Style.
62951 * @param {ol.Feature} feature Feature.
62952 * @private
62953 */
62954ol.renderer.vector.renderMultiPolygonGeometry_ = function(replayGroup, geometry, style, feature) {
62955 var fillStyle = style.getFill();
62956 var strokeStyle = style.getStroke();
62957 if (strokeStyle || fillStyle) {
62958 var polygonReplay = replayGroup.getReplay(
62959 style.getZIndex(), ol.render.ReplayType.POLYGON);
62960 polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
62961 polygonReplay.drawMultiPolygon(geometry, feature);
62962 }
62963 var textStyle = style.getText();
62964 if (textStyle) {
62965 var textReplay = replayGroup.getReplay(
62966 style.getZIndex(), ol.render.ReplayType.TEXT);
62967 textReplay.setTextStyle(textStyle);
62968 var flatInteriorPointCoordinates = geometry.getFlatInteriorPoints();
62969 textReplay.drawText(flatInteriorPointCoordinates, 0,
62970 flatInteriorPointCoordinates.length, 2, geometry, feature);
62971 }
62972};
62973
62974
62975/**
62976 * @param {ol.render.ReplayGroup} replayGroup Replay group.
62977 * @param {ol.geom.Point|ol.render.Feature} geometry Geometry.
62978 * @param {ol.style.Style} style Style.
62979 * @param {ol.Feature|ol.render.Feature} feature Feature.
62980 * @private
62981 */
62982ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style, feature) {
62983 var imageStyle = style.getImage();
62984 if (imageStyle) {
62985 if (imageStyle.getImageState() != ol.ImageState.LOADED) {
62986 return;
62987 }
62988 var imageReplay = replayGroup.getReplay(
62989 style.getZIndex(), ol.render.ReplayType.IMAGE);
62990 imageReplay.setImageStyle(imageStyle);
62991 imageReplay.drawPoint(geometry, feature);
62992 }
62993 var textStyle = style.getText();
62994 if (textStyle) {
62995 var textReplay = replayGroup.getReplay(
62996 style.getZIndex(), ol.render.ReplayType.TEXT);
62997 textReplay.setTextStyle(textStyle);
62998 textReplay.drawText(geometry.getFlatCoordinates(), 0, 2, 2, geometry,
62999 feature);
63000 }
63001};
63002
63003
63004/**
63005 * @param {ol.render.ReplayGroup} replayGroup Replay group.
63006 * @param {ol.geom.MultiPoint|ol.render.Feature} geometry Geometry.
63007 * @param {ol.style.Style} style Style.
63008 * @param {ol.Feature|ol.render.Feature} feature Feature.
63009 * @private
63010 */
63011ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, style, feature) {
63012 var imageStyle = style.getImage();
63013 if (imageStyle) {
63014 if (imageStyle.getImageState() != ol.ImageState.LOADED) {
63015 return;
63016 }
63017 var imageReplay = replayGroup.getReplay(
63018 style.getZIndex(), ol.render.ReplayType.IMAGE);
63019 imageReplay.setImageStyle(imageStyle);
63020 imageReplay.drawMultiPoint(geometry, feature);
63021 }
63022 var textStyle = style.getText();
63023 if (textStyle) {
63024 var textReplay = replayGroup.getReplay(
63025 style.getZIndex(), ol.render.ReplayType.TEXT);
63026 textReplay.setTextStyle(textStyle);
63027 var flatCoordinates = geometry.getFlatCoordinates();
63028 textReplay.drawText(flatCoordinates, 0, flatCoordinates.length,
63029 geometry.getStride(), geometry, feature);
63030 }
63031};
63032
63033
63034/**
63035 * @param {ol.render.ReplayGroup} replayGroup Replay group.
63036 * @param {ol.geom.Polygon|ol.render.Feature} geometry Geometry.
63037 * @param {ol.style.Style} style Style.
63038 * @param {ol.Feature|ol.render.Feature} feature Feature.
63039 * @private
63040 */
63041ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, style, feature) {
63042 var fillStyle = style.getFill();
63043 var strokeStyle = style.getStroke();
63044 if (fillStyle || strokeStyle) {
63045 var polygonReplay = replayGroup.getReplay(
63046 style.getZIndex(), ol.render.ReplayType.POLYGON);
63047 polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
63048 polygonReplay.drawPolygon(geometry, feature);
63049 }
63050 var textStyle = style.getText();
63051 if (textStyle) {
63052 var textReplay = replayGroup.getReplay(
63053 style.getZIndex(), ol.render.ReplayType.TEXT);
63054 textReplay.setTextStyle(textStyle);
63055 textReplay.drawText(
63056 geometry.getFlatInteriorPoint(), 0, 2, 2, geometry, feature);
63057 }
63058};
63059
63060
63061/**
63062 * @const
63063 * @private
63064 * @type {Object.<ol.geom.GeometryType,
63065 * function(ol.render.ReplayGroup, ol.geom.Geometry,
63066 * ol.style.Style, Object)>}
63067 */
63068ol.renderer.vector.GEOMETRY_RENDERERS_ = {
63069 'Point': ol.renderer.vector.renderPointGeometry_,
63070 'LineString': ol.renderer.vector.renderLineStringGeometry_,
63071 'Polygon': ol.renderer.vector.renderPolygonGeometry_,
63072 'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_,
63073 'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_,
63074 'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_,
63075 'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_,
63076 'Circle': ol.renderer.vector.renderCircleGeometry_
63077};
63078
63079goog.provide('ol.renderer.canvas.VectorLayer');
63080
63081goog.require('ol');
63082goog.require('ol.ViewHint');
63083goog.require('ol.dom');
63084goog.require('ol.extent');
63085goog.require('ol.render.EventType');
63086goog.require('ol.render.canvas');
63087goog.require('ol.render.canvas.ReplayGroup');
63088goog.require('ol.renderer.canvas.Layer');
63089goog.require('ol.renderer.vector');
63090
63091
63092/**
63093 * @constructor
63094 * @extends {ol.renderer.canvas.Layer}
63095 * @param {ol.layer.Vector} vectorLayer Vector layer.
63096 */
63097ol.renderer.canvas.VectorLayer = function(vectorLayer) {
63098
63099 ol.renderer.canvas.Layer.call(this, vectorLayer);
63100
63101 /**
63102 * @private
63103 * @type {boolean}
63104 */
63105 this.dirty_ = false;
63106
63107 /**
63108 * @private
63109 * @type {number}
63110 */
63111 this.renderedRevision_ = -1;
63112
63113 /**
63114 * @private
63115 * @type {number}
63116 */
63117 this.renderedResolution_ = NaN;
63118
63119 /**
63120 * @private
63121 * @type {ol.Extent}
63122 */
63123 this.renderedExtent_ = ol.extent.createEmpty();
63124
63125 /**
63126 * @private
63127 * @type {function(ol.Feature, ol.Feature): number|null}
63128 */
63129 this.renderedRenderOrder_ = null;
63130
63131 /**
63132 * @private
63133 * @type {ol.render.canvas.ReplayGroup}
63134 */
63135 this.replayGroup_ = null;
63136
63137 /**
63138 * @private
63139 * @type {CanvasRenderingContext2D}
63140 */
63141 this.context_ = ol.dom.createCanvasContext2D();
63142
63143};
63144ol.inherits(ol.renderer.canvas.VectorLayer, ol.renderer.canvas.Layer);
63145
63146
63147/**
63148 * @inheritDoc
63149 */
63150ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {
63151
63152 var extent = frameState.extent;
63153 var pixelRatio = frameState.pixelRatio;
63154 var skippedFeatureUids = layerState.managed ?
63155 frameState.skippedFeatureUids : {};
63156 var viewState = frameState.viewState;
63157 var projection = viewState.projection;
63158 var rotation = viewState.rotation;
63159 var projectionExtent = projection.getExtent();
63160 var vectorSource = /** @type {ol.source.Vector} */ (this.getLayer().getSource());
63161
63162 var transform = this.getTransform(frameState, 0);
63163
63164 this.preCompose(context, frameState, transform);
63165
63166 // clipped rendering if layer extent is set
63167 var clipExtent = layerState.extent;
63168 var clipped = clipExtent !== undefined;
63169 if (clipped) {
63170 this.clip(context, frameState, /** @type {ol.Extent} */ (clipExtent));
63171 }
63172 var replayGroup = this.replayGroup_;
63173 if (replayGroup && !replayGroup.isEmpty()) {
63174 var layer = this.getLayer();
63175 var drawOffsetX = 0;
63176 var drawOffsetY = 0;
63177 var replayContext;
63178 var transparentLayer = layerState.opacity !== 1;
63179 var hasRenderListeners = layer.hasListener(ol.render.EventType.RENDER);
63180 if (transparentLayer || hasRenderListeners) {
63181 var drawWidth = context.canvas.width;
63182 var drawHeight = context.canvas.height;
63183 if (rotation) {
63184 var drawSize = Math.round(Math.sqrt(drawWidth * drawWidth + drawHeight * drawHeight));
63185 drawOffsetX = (drawSize - drawWidth) / 2;
63186 drawOffsetY = (drawSize - drawHeight) / 2;
63187 drawWidth = drawHeight = drawSize;
63188 }
63189 // resize and clear
63190 this.context_.canvas.width = drawWidth;
63191 this.context_.canvas.height = drawHeight;
63192 replayContext = this.context_;
63193 } else {
63194 replayContext = context;
63195 }
63196
63197 var alpha = replayContext.globalAlpha;
63198 if (!transparentLayer) {
63199 // for performance reasons, context.save / context.restore is not used
63200 // to save and restore the transformation matrix and the opacity.
63201 // see http://jsperf.com/context-save-restore-versus-variable
63202 replayContext.globalAlpha = layerState.opacity;
63203 }
63204
63205 if (replayContext != context) {
63206 replayContext.translate(drawOffsetX, drawOffsetY);
63207 }
63208
63209 var width = frameState.size[0] * pixelRatio;
63210 var height = frameState.size[1] * pixelRatio;
63211 ol.render.canvas.rotateAtOffset(replayContext, -rotation,
63212 width / 2, height / 2);
63213 replayGroup.replay(replayContext, pixelRatio, transform, rotation,
63214 skippedFeatureUids);
63215 if (vectorSource.getWrapX() && projection.canWrapX() &&
63216 !ol.extent.containsExtent(projectionExtent, extent)) {
63217 var startX = extent[0];
63218 var worldWidth = ol.extent.getWidth(projectionExtent);
63219 var world = 0;
63220 var offsetX;
63221 while (startX < projectionExtent[0]) {
63222 --world;
63223 offsetX = worldWidth * world;
63224 transform = this.getTransform(frameState, offsetX);
63225 replayGroup.replay(replayContext, pixelRatio, transform, rotation,
63226 skippedFeatureUids);
63227 startX += worldWidth;
63228 }
63229 world = 0;
63230 startX = extent[2];
63231 while (startX > projectionExtent[2]) {
63232 ++world;
63233 offsetX = worldWidth * world;
63234 transform = this.getTransform(frameState, offsetX);
63235 replayGroup.replay(replayContext, pixelRatio, transform, rotation,
63236 skippedFeatureUids);
63237 startX -= worldWidth;
63238 }
63239 // restore original transform for render and compose events
63240 transform = this.getTransform(frameState, 0);
63241 }
63242 ol.render.canvas.rotateAtOffset(replayContext, rotation,
63243 width / 2, height / 2);
63244
63245 if (replayContext != context) {
63246 if (hasRenderListeners) {
63247 this.dispatchRenderEvent(replayContext, frameState, transform);
63248 }
63249 if (transparentLayer) {
63250 var mainContextAlpha = context.globalAlpha;
63251 context.globalAlpha = layerState.opacity;
63252 context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);
63253 context.globalAlpha = mainContextAlpha;
63254 } else {
63255 context.drawImage(replayContext.canvas, -drawOffsetX, -drawOffsetY);
63256 }
63257 replayContext.translate(-drawOffsetX, -drawOffsetY);
63258 }
63259
63260 if (!transparentLayer) {
63261 replayContext.globalAlpha = alpha;
63262 }
63263 }
63264
63265 if (clipped) {
63266 context.restore();
63267 }
63268 this.postCompose(context, frameState, layerState, transform);
63269
63270};
63271
63272
63273/**
63274 * @inheritDoc
63275 */
63276ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {
63277 if (!this.replayGroup_) {
63278 return undefined;
63279 } else {
63280 var resolution = frameState.viewState.resolution;
63281 var rotation = frameState.viewState.rotation;
63282 var layer = this.getLayer();
63283 /** @type {Object.<string, boolean>} */
63284 var features = {};
63285 return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution,
63286 rotation, hitTolerance, {},
63287 /**
63288 * @param {ol.Feature|ol.render.Feature} feature Feature.
63289 * @return {?} Callback result.
63290 */
63291 function(feature) {
63292 var key = ol.getUid(feature).toString();
63293 if (!(key in features)) {
63294 features[key] = true;
63295 return callback.call(thisArg, feature, layer);
63296 }
63297 });
63298 }
63299};
63300
63301
63302/**
63303 * Handle changes in image style state.
63304 * @param {ol.events.Event} event Image style change event.
63305 * @private
63306 */
63307ol.renderer.canvas.VectorLayer.prototype.handleStyleImageChange_ = function(event) {
63308 this.renderIfReadyAndVisible();
63309};
63310
63311
63312/**
63313 * @inheritDoc
63314 */
63315ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, layerState) {
63316
63317 var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
63318 var vectorSource = vectorLayer.getSource();
63319
63320 this.updateAttributions(
63321 frameState.attributions, vectorSource.getAttributions());
63322 this.updateLogos(frameState, vectorSource);
63323
63324 var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
63325 var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
63326 var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
63327 var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
63328
63329 if (!this.dirty_ && (!updateWhileAnimating && animating) ||
63330 (!updateWhileInteracting && interacting)) {
63331 return true;
63332 }
63333
63334 var frameStateExtent = frameState.extent;
63335 var viewState = frameState.viewState;
63336 var projection = viewState.projection;
63337 var resolution = viewState.resolution;
63338 var pixelRatio = frameState.pixelRatio;
63339 var vectorLayerRevision = vectorLayer.getRevision();
63340 var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
63341 var vectorLayerRenderOrder = vectorLayer.getRenderOrder();
63342
63343 if (vectorLayerRenderOrder === undefined) {
63344 vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;
63345 }
63346
63347 var extent = ol.extent.buffer(frameStateExtent,
63348 vectorLayerRenderBuffer * resolution);
63349 var projectionExtent = viewState.projection.getExtent();
63350
63351 if (vectorSource.getWrapX() && viewState.projection.canWrapX() &&
63352 !ol.extent.containsExtent(projectionExtent, frameState.extent)) {
63353 // For the replay group, we need an extent that intersects the real world
63354 // (-180° to +180°). To support geometries in a coordinate range from -540°
63355 // to +540°, we add at least 1 world width on each side of the projection
63356 // extent. If the viewport is wider than the world, we need to add half of
63357 // the viewport width to make sure we cover the whole viewport.
63358 var worldWidth = ol.extent.getWidth(projectionExtent);
63359 var buffer = Math.max(ol.extent.getWidth(extent) / 2, worldWidth);
63360 extent[0] = projectionExtent[0] - buffer;
63361 extent[2] = projectionExtent[2] + buffer;
63362 }
63363
63364 if (!this.dirty_ &&
63365 this.renderedResolution_ == resolution &&
63366 this.renderedRevision_ == vectorLayerRevision &&
63367 this.renderedRenderOrder_ == vectorLayerRenderOrder &&
63368 ol.extent.containsExtent(this.renderedExtent_, extent)) {
63369 return true;
63370 }
63371
63372 this.replayGroup_ = null;
63373
63374 this.dirty_ = false;
63375
63376 var replayGroup = new ol.render.canvas.ReplayGroup(
63377 ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
63378 resolution, vectorSource.getOverlaps(), vectorLayer.getRenderBuffer());
63379 vectorSource.loadFeatures(extent, resolution, projection);
63380 /**
63381 * @param {ol.Feature} feature Feature.
63382 * @this {ol.renderer.canvas.VectorLayer}
63383 */
63384 var renderFeature = function(feature) {
63385 var styles;
63386 var styleFunction = feature.getStyleFunction();
63387 if (styleFunction) {
63388 styles = styleFunction.call(feature, resolution);
63389 } else {
63390 styleFunction = vectorLayer.getStyleFunction();
63391 if (styleFunction) {
63392 styles = styleFunction(feature, resolution);
63393 }
63394 }
63395 if (styles) {
63396 var dirty = this.renderFeature(
63397 feature, resolution, pixelRatio, styles, replayGroup);
63398 this.dirty_ = this.dirty_ || dirty;
63399 }
63400 }.bind(this);
63401 if (vectorLayerRenderOrder) {
63402 /** @type {Array.<ol.Feature>} */
63403 var features = [];
63404 vectorSource.forEachFeatureInExtent(extent,
63405 /**
63406 * @param {ol.Feature} feature Feature.
63407 */
63408 function(feature) {
63409 features.push(feature);
63410 }, this);
63411 features.sort(vectorLayerRenderOrder);
63412 for (var i = 0, ii = features.length; i < ii; ++i) {
63413 renderFeature(features[i]);
63414 }
63415 } else {
63416 vectorSource.forEachFeatureInExtent(extent, renderFeature, this);
63417 }
63418 replayGroup.finish();
63419
63420 this.renderedResolution_ = resolution;
63421 this.renderedRevision_ = vectorLayerRevision;
63422 this.renderedRenderOrder_ = vectorLayerRenderOrder;
63423 this.renderedExtent_ = extent;
63424 this.replayGroup_ = replayGroup;
63425
63426 return true;
63427};
63428
63429
63430/**
63431 * @param {ol.Feature} feature Feature.
63432 * @param {number} resolution Resolution.
63433 * @param {number} pixelRatio Pixel ratio.
63434 * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
63435 * styles.
63436 * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
63437 * @return {boolean} `true` if an image is loading.
63438 */
63439ol.renderer.canvas.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
63440 if (!styles) {
63441 return false;
63442 }
63443 var loading = false;
63444 if (Array.isArray(styles)) {
63445 for (var i = 0, ii = styles.length; i < ii; ++i) {
63446 loading = ol.renderer.vector.renderFeature(
63447 replayGroup, feature, styles[i],
63448 ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
63449 this.handleStyleImageChange_, this) || loading;
63450 }
63451 } else {
63452 loading = ol.renderer.vector.renderFeature(
63453 replayGroup, feature, styles,
63454 ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
63455 this.handleStyleImageChange_, this) || loading;
63456 }
63457 return loading;
63458};
63459
63460// This file is automatically generated, do not edit
63461/* eslint openlayers-internal/no-missing-requires: 0 */
63462goog.provide('ol.renderer.webgl.defaultmapshader');
63463
63464goog.require('ol');
63465goog.require('ol.webgl.Fragment');
63466goog.require('ol.webgl.Vertex');
63467
63468if (ol.ENABLE_WEBGL) {
63469
63470 /**
63471 * @constructor
63472 * @extends {ol.webgl.Fragment}
63473 * @struct
63474 */
63475 ol.renderer.webgl.defaultmapshader.Fragment = function() {
63476 ol.webgl.Fragment.call(this, ol.renderer.webgl.defaultmapshader.Fragment.SOURCE);
63477 };
63478 ol.inherits(ol.renderer.webgl.defaultmapshader.Fragment, ol.webgl.Fragment);
63479
63480
63481 /**
63482 * @const
63483 * @type {string}
63484 */
63485 ol.renderer.webgl.defaultmapshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\n\n\nuniform float u_opacity;\nuniform sampler2D u_texture;\n\nvoid main(void) {\n vec4 texColor = texture2D(u_texture, v_texCoord);\n gl_FragColor.rgb = texColor.rgb;\n gl_FragColor.a = texColor.a * u_opacity;\n}\n';
63486
63487
63488 /**
63489 * @const
63490 * @type {string}
63491 */
63492 ol.renderer.webgl.defaultmapshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform float f;uniform sampler2D g;void main(void){vec4 texColor=texture2D(g,a);gl_FragColor.rgb=texColor.rgb;gl_FragColor.a=texColor.a*f;}';
63493
63494
63495 /**
63496 * @const
63497 * @type {string}
63498 */
63499 ol.renderer.webgl.defaultmapshader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
63500 ol.renderer.webgl.defaultmapshader.Fragment.DEBUG_SOURCE :
63501 ol.renderer.webgl.defaultmapshader.Fragment.OPTIMIZED_SOURCE;
63502
63503
63504 ol.renderer.webgl.defaultmapshader.fragment = new ol.renderer.webgl.defaultmapshader.Fragment();
63505
63506
63507 /**
63508 * @constructor
63509 * @extends {ol.webgl.Vertex}
63510 * @struct
63511 */
63512 ol.renderer.webgl.defaultmapshader.Vertex = function() {
63513 ol.webgl.Vertex.call(this, ol.renderer.webgl.defaultmapshader.Vertex.SOURCE);
63514 };
63515 ol.inherits(ol.renderer.webgl.defaultmapshader.Vertex, ol.webgl.Vertex);
63516
63517
63518 /**
63519 * @const
63520 * @type {string}
63521 */
63522 ol.renderer.webgl.defaultmapshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\n\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\n\nuniform mat4 u_texCoordMatrix;\nuniform mat4 u_projectionMatrix;\n\nvoid main(void) {\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.);\n v_texCoord = (u_texCoordMatrix * vec4(a_texCoord, 0., 1.)).st;\n}\n\n\n';
63523
63524
63525 /**
63526 * @const
63527 * @type {string}
63528 */
63529 ol.renderer.webgl.defaultmapshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;attribute vec2 b;attribute vec2 c;uniform mat4 d;uniform mat4 e;void main(void){gl_Position=e*vec4(b,0.,1.);a=(d*vec4(c,0.,1.)).st;}';
63530
63531
63532 /**
63533 * @const
63534 * @type {string}
63535 */
63536 ol.renderer.webgl.defaultmapshader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
63537 ol.renderer.webgl.defaultmapshader.Vertex.DEBUG_SOURCE :
63538 ol.renderer.webgl.defaultmapshader.Vertex.OPTIMIZED_SOURCE;
63539
63540
63541 ol.renderer.webgl.defaultmapshader.vertex = new ol.renderer.webgl.defaultmapshader.Vertex();
63542
63543
63544 /**
63545 * @constructor
63546 * @param {WebGLRenderingContext} gl GL.
63547 * @param {WebGLProgram} program Program.
63548 * @struct
63549 */
63550 ol.renderer.webgl.defaultmapshader.Locations = function(gl, program) {
63551
63552 /**
63553 * @type {WebGLUniformLocation}
63554 */
63555 this.u_opacity = gl.getUniformLocation(
63556 program, ol.DEBUG_WEBGL ? 'u_opacity' : 'f');
63557
63558 /**
63559 * @type {WebGLUniformLocation}
63560 */
63561 this.u_projectionMatrix = gl.getUniformLocation(
63562 program, ol.DEBUG_WEBGL ? 'u_projectionMatrix' : 'e');
63563
63564 /**
63565 * @type {WebGLUniformLocation}
63566 */
63567 this.u_texCoordMatrix = gl.getUniformLocation(
63568 program, ol.DEBUG_WEBGL ? 'u_texCoordMatrix' : 'd');
63569
63570 /**
63571 * @type {WebGLUniformLocation}
63572 */
63573 this.u_texture = gl.getUniformLocation(
63574 program, ol.DEBUG_WEBGL ? 'u_texture' : 'g');
63575
63576 /**
63577 * @type {number}
63578 */
63579 this.a_position = gl.getAttribLocation(
63580 program, ol.DEBUG_WEBGL ? 'a_position' : 'b');
63581
63582 /**
63583 * @type {number}
63584 */
63585 this.a_texCoord = gl.getAttribLocation(
63586 program, ol.DEBUG_WEBGL ? 'a_texCoord' : 'c');
63587 };
63588
63589}
63590
63591goog.provide('ol.renderer.webgl.Layer');
63592
63593goog.require('ol');
63594goog.require('ol.render.Event');
63595goog.require('ol.render.EventType');
63596goog.require('ol.render.webgl.Immediate');
63597goog.require('ol.renderer.Layer');
63598goog.require('ol.renderer.webgl.defaultmapshader');
63599goog.require('ol.transform');
63600goog.require('ol.vec.Mat4');
63601goog.require('ol.webgl');
63602goog.require('ol.webgl.Buffer');
63603goog.require('ol.webgl.Context');
63604
63605
63606if (ol.ENABLE_WEBGL) {
63607
63608 /**
63609 * @constructor
63610 * @abstract
63611 * @extends {ol.renderer.Layer}
63612 * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
63613 * @param {ol.layer.Layer} layer Layer.
63614 */
63615 ol.renderer.webgl.Layer = function(mapRenderer, layer) {
63616
63617 ol.renderer.Layer.call(this, layer);
63618
63619 /**
63620 * @protected
63621 * @type {ol.renderer.webgl.Map}
63622 */
63623 this.mapRenderer = mapRenderer;
63624
63625 /**
63626 * @private
63627 * @type {ol.webgl.Buffer}
63628 */
63629 this.arrayBuffer_ = new ol.webgl.Buffer([
63630 -1, -1, 0, 0,
63631 1, -1, 1, 0,
63632 -1, 1, 0, 1,
63633 1, 1, 1, 1
63634 ]);
63635
63636 /**
63637 * @protected
63638 * @type {WebGLTexture}
63639 */
63640 this.texture = null;
63641
63642 /**
63643 * @protected
63644 * @type {WebGLFramebuffer}
63645 */
63646 this.framebuffer = null;
63647
63648 /**
63649 * @protected
63650 * @type {number|undefined}
63651 */
63652 this.framebufferDimension = undefined;
63653
63654 /**
63655 * @protected
63656 * @type {ol.Transform}
63657 */
63658 this.texCoordMatrix = ol.transform.create();
63659
63660 /**
63661 * @protected
63662 * @type {ol.Transform}
63663 */
63664 this.projectionMatrix = ol.transform.create();
63665
63666 /**
63667 * @type {Array.<number>}
63668 * @private
63669 */
63670 this.tmpMat4_ = ol.vec.Mat4.create();
63671
63672 /**
63673 * @private
63674 * @type {ol.renderer.webgl.defaultmapshader.Locations}
63675 */
63676 this.defaultLocations_ = null;
63677
63678 };
63679 ol.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);
63680
63681
63682 /**
63683 * @param {olx.FrameState} frameState Frame state.
63684 * @param {number} framebufferDimension Framebuffer dimension.
63685 * @protected
63686 */
63687 ol.renderer.webgl.Layer.prototype.bindFramebuffer = function(frameState, framebufferDimension) {
63688
63689 var gl = this.mapRenderer.getGL();
63690
63691 if (this.framebufferDimension === undefined ||
63692 this.framebufferDimension != framebufferDimension) {
63693 /**
63694 * @param {WebGLRenderingContext} gl GL.
63695 * @param {WebGLFramebuffer} framebuffer Framebuffer.
63696 * @param {WebGLTexture} texture Texture.
63697 */
63698 var postRenderFunction = function(gl, framebuffer, texture) {
63699 if (!gl.isContextLost()) {
63700 gl.deleteFramebuffer(framebuffer);
63701 gl.deleteTexture(texture);
63702 }
63703 }.bind(null, gl, this.framebuffer, this.texture);
63704
63705 frameState.postRenderFunctions.push(
63706 /** @type {ol.PostRenderFunction} */ (postRenderFunction)
63707 );
63708
63709 var texture = ol.webgl.Context.createEmptyTexture(
63710 gl, framebufferDimension, framebufferDimension);
63711
63712 var framebuffer = gl.createFramebuffer();
63713 gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, framebuffer);
63714 gl.framebufferTexture2D(ol.webgl.FRAMEBUFFER,
63715 ol.webgl.COLOR_ATTACHMENT0, ol.webgl.TEXTURE_2D, texture, 0);
63716
63717 this.texture = texture;
63718 this.framebuffer = framebuffer;
63719 this.framebufferDimension = framebufferDimension;
63720
63721 } else {
63722 gl.bindFramebuffer(ol.webgl.FRAMEBUFFER, this.framebuffer);
63723 }
63724
63725 };
63726
63727
63728 /**
63729 * @param {olx.FrameState} frameState Frame state.
63730 * @param {ol.LayerState} layerState Layer state.
63731 * @param {ol.webgl.Context} context Context.
63732 */
63733 ol.renderer.webgl.Layer.prototype.composeFrame = function(frameState, layerState, context) {
63734
63735 this.dispatchComposeEvent_(
63736 ol.render.EventType.PRECOMPOSE, context, frameState);
63737
63738 context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.arrayBuffer_);
63739
63740 var gl = context.getGL();
63741
63742 var fragmentShader = ol.renderer.webgl.defaultmapshader.fragment;
63743 var vertexShader = ol.renderer.webgl.defaultmapshader.vertex;
63744
63745 var program = context.getProgram(fragmentShader, vertexShader);
63746
63747 var locations;
63748 if (!this.defaultLocations_) {
63749 // eslint-disable-next-line openlayers-internal/no-missing-requires
63750 locations = new ol.renderer.webgl.defaultmapshader.Locations(gl, program);
63751 this.defaultLocations_ = locations;
63752 } else {
63753 locations = this.defaultLocations_;
63754 }
63755
63756 if (context.useProgram(program)) {
63757 gl.enableVertexAttribArray(locations.a_position);
63758 gl.vertexAttribPointer(
63759 locations.a_position, 2, ol.webgl.FLOAT, false, 16, 0);
63760 gl.enableVertexAttribArray(locations.a_texCoord);
63761 gl.vertexAttribPointer(
63762 locations.a_texCoord, 2, ol.webgl.FLOAT, false, 16, 8);
63763 gl.uniform1i(locations.u_texture, 0);
63764 }
63765
63766 gl.uniformMatrix4fv(locations.u_texCoordMatrix, false,
63767 ol.vec.Mat4.fromTransform(this.tmpMat4_, this.getTexCoordMatrix()));
63768 gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
63769 ol.vec.Mat4.fromTransform(this.tmpMat4_, this.getProjectionMatrix()));
63770 gl.uniform1f(locations.u_opacity, layerState.opacity);
63771 gl.bindTexture(ol.webgl.TEXTURE_2D, this.getTexture());
63772 gl.drawArrays(ol.webgl.TRIANGLE_STRIP, 0, 4);
63773
63774 this.dispatchComposeEvent_(
63775 ol.render.EventType.POSTCOMPOSE, context, frameState);
63776
63777 };
63778
63779
63780 /**
63781 * @param {ol.render.EventType} type Event type.
63782 * @param {ol.webgl.Context} context WebGL context.
63783 * @param {olx.FrameState} frameState Frame state.
63784 * @private
63785 */
63786 ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ = function(type, context, frameState) {
63787 var layer = this.getLayer();
63788 if (layer.hasListener(type)) {
63789 var viewState = frameState.viewState;
63790 var resolution = viewState.resolution;
63791 var pixelRatio = frameState.pixelRatio;
63792 var extent = frameState.extent;
63793 var center = viewState.center;
63794 var rotation = viewState.rotation;
63795 var size = frameState.size;
63796
63797 var render = new ol.render.webgl.Immediate(
63798 context, center, resolution, rotation, size, extent, pixelRatio);
63799 var composeEvent = new ol.render.Event(
63800 type, render, frameState, null, context);
63801 layer.dispatchEvent(composeEvent);
63802 }
63803 };
63804
63805
63806 /**
63807 * @return {!ol.Transform} Matrix.
63808 */
63809 ol.renderer.webgl.Layer.prototype.getTexCoordMatrix = function() {
63810 return this.texCoordMatrix;
63811 };
63812
63813
63814 /**
63815 * @return {WebGLTexture} Texture.
63816 */
63817 ol.renderer.webgl.Layer.prototype.getTexture = function() {
63818 return this.texture;
63819 };
63820
63821
63822 /**
63823 * @return {!ol.Transform} Matrix.
63824 */
63825 ol.renderer.webgl.Layer.prototype.getProjectionMatrix = function() {
63826 return this.projectionMatrix;
63827 };
63828
63829
63830 /**
63831 * Handle webglcontextlost.
63832 */
63833 ol.renderer.webgl.Layer.prototype.handleWebGLContextLost = function() {
63834 this.texture = null;
63835 this.framebuffer = null;
63836 this.framebufferDimension = undefined;
63837 };
63838
63839
63840 /**
63841 * @abstract
63842 * @param {olx.FrameState} frameState Frame state.
63843 * @param {ol.LayerState} layerState Layer state.
63844 * @param {ol.webgl.Context} context Context.
63845 * @return {boolean} whether composeFrame should be called.
63846 */
63847 ol.renderer.webgl.Layer.prototype.prepareFrame = function(frameState, layerState, context) {};
63848
63849
63850 /**
63851 * @abstract
63852 * @param {ol.Pixel} pixel Pixel.
63853 * @param {olx.FrameState} frameState FrameState.
63854 * @param {function(this: S, ol.layer.Layer, (Uint8ClampedArray|Uint8Array)): T} callback Layer
63855 * callback.
63856 * @param {S} thisArg Value to use as `this` when executing `callback`.
63857 * @return {T|undefined} Callback result.
63858 * @template S,T,U
63859 */
63860 ol.renderer.webgl.Layer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {};
63861
63862}
63863
63864goog.provide('ol.renderer.webgl.VectorLayer');
63865
63866goog.require('ol');
63867goog.require('ol.ViewHint');
63868goog.require('ol.extent');
63869goog.require('ol.render.webgl.ReplayGroup');
63870goog.require('ol.renderer.vector');
63871goog.require('ol.renderer.webgl.Layer');
63872goog.require('ol.transform');
63873
63874
63875if (ol.ENABLE_WEBGL) {
63876
63877 /**
63878 * @constructor
63879 * @extends {ol.renderer.webgl.Layer}
63880 * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
63881 * @param {ol.layer.Vector} vectorLayer Vector layer.
63882 */
63883 ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {
63884
63885 ol.renderer.webgl.Layer.call(this, mapRenderer, vectorLayer);
63886
63887 /**
63888 * @private
63889 * @type {boolean}
63890 */
63891 this.dirty_ = false;
63892
63893 /**
63894 * @private
63895 * @type {number}
63896 */
63897 this.renderedRevision_ = -1;
63898
63899 /**
63900 * @private
63901 * @type {number}
63902 */
63903 this.renderedResolution_ = NaN;
63904
63905 /**
63906 * @private
63907 * @type {ol.Extent}
63908 */
63909 this.renderedExtent_ = ol.extent.createEmpty();
63910
63911 /**
63912 * @private
63913 * @type {function(ol.Feature, ol.Feature): number|null}
63914 */
63915 this.renderedRenderOrder_ = null;
63916
63917 /**
63918 * @private
63919 * @type {ol.render.webgl.ReplayGroup}
63920 */
63921 this.replayGroup_ = null;
63922
63923 /**
63924 * The last layer state.
63925 * @private
63926 * @type {?ol.LayerState}
63927 */
63928 this.layerState_ = null;
63929
63930 };
63931 ol.inherits(ol.renderer.webgl.VectorLayer, ol.renderer.webgl.Layer);
63932
63933
63934 /**
63935 * @inheritDoc
63936 */
63937 ol.renderer.webgl.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {
63938 this.layerState_ = layerState;
63939 var viewState = frameState.viewState;
63940 var replayGroup = this.replayGroup_;
63941 var size = frameState.size;
63942 var pixelRatio = frameState.pixelRatio;
63943 var gl = this.mapRenderer.getGL();
63944 if (replayGroup && !replayGroup.isEmpty()) {
63945 gl.enable(gl.SCISSOR_TEST);
63946 gl.scissor(0, 0, size[0] * pixelRatio, size[1] * pixelRatio);
63947 replayGroup.replay(context,
63948 viewState.center, viewState.resolution, viewState.rotation,
63949 size, pixelRatio, layerState.opacity,
63950 layerState.managed ? frameState.skippedFeatureUids : {});
63951 gl.disable(gl.SCISSOR_TEST);
63952 }
63953
63954 };
63955
63956
63957 /**
63958 * @inheritDoc
63959 */
63960 ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {
63961 var replayGroup = this.replayGroup_;
63962 if (replayGroup) {
63963 var context = this.mapRenderer.getContext();
63964 replayGroup.getDeleteResourcesFunction(context)();
63965 this.replayGroup_ = null;
63966 }
63967 ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);
63968 };
63969
63970
63971 /**
63972 * @inheritDoc
63973 */
63974 ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {
63975 if (!this.replayGroup_ || !this.layerState_) {
63976 return undefined;
63977 } else {
63978 var context = this.mapRenderer.getContext();
63979 var viewState = frameState.viewState;
63980 var layer = this.getLayer();
63981 var layerState = this.layerState_;
63982 /** @type {Object.<string, boolean>} */
63983 var features = {};
63984 return this.replayGroup_.forEachFeatureAtCoordinate(coordinate,
63985 context, viewState.center, viewState.resolution, viewState.rotation,
63986 frameState.size, frameState.pixelRatio, layerState.opacity,
63987 {},
63988 /**
63989 * @param {ol.Feature|ol.render.Feature} feature Feature.
63990 * @return {?} Callback result.
63991 */
63992 function(feature) {
63993 var key = ol.getUid(feature).toString();
63994 if (!(key in features)) {
63995 features[key] = true;
63996 return callback.call(thisArg, feature, layer);
63997 }
63998 });
63999 }
64000 };
64001
64002
64003 /**
64004 * @inheritDoc
64005 */
64006 ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {
64007 if (!this.replayGroup_ || !this.layerState_) {
64008 return false;
64009 } else {
64010 var context = this.mapRenderer.getContext();
64011 var viewState = frameState.viewState;
64012 var layerState = this.layerState_;
64013 return this.replayGroup_.hasFeatureAtCoordinate(coordinate,
64014 context, viewState.center, viewState.resolution, viewState.rotation,
64015 frameState.size, frameState.pixelRatio, layerState.opacity,
64016 frameState.skippedFeatureUids);
64017 }
64018 };
64019
64020
64021 /**
64022 * @inheritDoc
64023 */
64024 ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
64025 var coordinate = ol.transform.apply(
64026 frameState.pixelToCoordinateTransform, pixel.slice());
64027 var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState);
64028
64029 if (hasFeature) {
64030 return callback.call(thisArg, this.getLayer(), null);
64031 } else {
64032 return undefined;
64033 }
64034 };
64035
64036
64037 /**
64038 * Handle changes in image style state.
64039 * @param {ol.events.Event} event Image style change event.
64040 * @private
64041 */
64042 ol.renderer.webgl.VectorLayer.prototype.handleStyleImageChange_ = function(event) {
64043 this.renderIfReadyAndVisible();
64044 };
64045
64046
64047 /**
64048 * @inheritDoc
64049 */
64050 ol.renderer.webgl.VectorLayer.prototype.prepareFrame = function(frameState, layerState, context) {
64051
64052 var vectorLayer = /** @type {ol.layer.Vector} */ (this.getLayer());
64053 var vectorSource = vectorLayer.getSource();
64054
64055 this.updateAttributions(
64056 frameState.attributions, vectorSource.getAttributions());
64057 this.updateLogos(frameState, vectorSource);
64058
64059 var animating = frameState.viewHints[ol.ViewHint.ANIMATING];
64060 var interacting = frameState.viewHints[ol.ViewHint.INTERACTING];
64061 var updateWhileAnimating = vectorLayer.getUpdateWhileAnimating();
64062 var updateWhileInteracting = vectorLayer.getUpdateWhileInteracting();
64063
64064 if (!this.dirty_ && (!updateWhileAnimating && animating) ||
64065 (!updateWhileInteracting && interacting)) {
64066 return true;
64067 }
64068
64069 var frameStateExtent = frameState.extent;
64070 var viewState = frameState.viewState;
64071 var projection = viewState.projection;
64072 var resolution = viewState.resolution;
64073 var pixelRatio = frameState.pixelRatio;
64074 var vectorLayerRevision = vectorLayer.getRevision();
64075 var vectorLayerRenderBuffer = vectorLayer.getRenderBuffer();
64076 var vectorLayerRenderOrder = vectorLayer.getRenderOrder();
64077
64078 if (vectorLayerRenderOrder === undefined) {
64079 vectorLayerRenderOrder = ol.renderer.vector.defaultOrder;
64080 }
64081
64082 var extent = ol.extent.buffer(frameStateExtent,
64083 vectorLayerRenderBuffer * resolution);
64084
64085 if (!this.dirty_ &&
64086 this.renderedResolution_ == resolution &&
64087 this.renderedRevision_ == vectorLayerRevision &&
64088 this.renderedRenderOrder_ == vectorLayerRenderOrder &&
64089 ol.extent.containsExtent(this.renderedExtent_, extent)) {
64090 return true;
64091 }
64092
64093 if (this.replayGroup_) {
64094 frameState.postRenderFunctions.push(
64095 this.replayGroup_.getDeleteResourcesFunction(context));
64096 }
64097
64098 this.dirty_ = false;
64099
64100 var replayGroup = new ol.render.webgl.ReplayGroup(
64101 ol.renderer.vector.getTolerance(resolution, pixelRatio),
64102 extent, vectorLayer.getRenderBuffer());
64103 vectorSource.loadFeatures(extent, resolution, projection);
64104 /**
64105 * @param {ol.Feature} feature Feature.
64106 * @this {ol.renderer.webgl.VectorLayer}
64107 */
64108 var renderFeature = function(feature) {
64109 var styles;
64110 var styleFunction = feature.getStyleFunction();
64111 if (styleFunction) {
64112 styles = styleFunction.call(feature, resolution);
64113 } else {
64114 styleFunction = vectorLayer.getStyleFunction();
64115 if (styleFunction) {
64116 styles = styleFunction(feature, resolution);
64117 }
64118 }
64119 if (styles) {
64120 var dirty = this.renderFeature(
64121 feature, resolution, pixelRatio, styles, replayGroup);
64122 this.dirty_ = this.dirty_ || dirty;
64123 }
64124 };
64125 if (vectorLayerRenderOrder) {
64126 /** @type {Array.<ol.Feature>} */
64127 var features = [];
64128 vectorSource.forEachFeatureInExtent(extent,
64129 /**
64130 * @param {ol.Feature} feature Feature.
64131 */
64132 function(feature) {
64133 features.push(feature);
64134 }, this);
64135 features.sort(vectorLayerRenderOrder);
64136 features.forEach(renderFeature, this);
64137 } else {
64138 vectorSource.forEachFeatureInExtent(extent, renderFeature, this);
64139 }
64140 replayGroup.finish(context);
64141
64142 this.renderedResolution_ = resolution;
64143 this.renderedRevision_ = vectorLayerRevision;
64144 this.renderedRenderOrder_ = vectorLayerRenderOrder;
64145 this.renderedExtent_ = extent;
64146 this.replayGroup_ = replayGroup;
64147
64148 return true;
64149 };
64150
64151
64152 /**
64153 * @param {ol.Feature} feature Feature.
64154 * @param {number} resolution Resolution.
64155 * @param {number} pixelRatio Pixel ratio.
64156 * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
64157 * styles.
64158 * @param {ol.render.webgl.ReplayGroup} replayGroup Replay group.
64159 * @return {boolean} `true` if an image is loading.
64160 */
64161 ol.renderer.webgl.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
64162 if (!styles) {
64163 return false;
64164 }
64165 var loading = false;
64166 if (Array.isArray(styles)) {
64167 for (var i = styles.length - 1, ii = 0; i >= ii; --i) {
64168 loading = ol.renderer.vector.renderFeature(
64169 replayGroup, feature, styles[i],
64170 ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
64171 this.handleStyleImageChange_, this) || loading;
64172 }
64173 } else {
64174 loading = ol.renderer.vector.renderFeature(
64175 replayGroup, feature, styles,
64176 ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
64177 this.handleStyleImageChange_, this) || loading;
64178 }
64179 return loading;
64180 };
64181
64182}
64183
64184goog.provide('ol.layer.Vector');
64185
64186goog.require('ol');
64187goog.require('ol.layer.Layer');
64188goog.require('ol.obj');
64189goog.require('ol.renderer.Type');
64190goog.require('ol.renderer.canvas.VectorLayer');
64191goog.require('ol.renderer.webgl.VectorLayer');
64192goog.require('ol.style.Style');
64193
64194
64195/**
64196 * @classdesc
64197 * Vector data that is rendered client-side.
64198 * Note that any property set in the options is set as a {@link ol.Object}
64199 * property on the layer object; for example, setting `title: 'My Title'` in the
64200 * options means that `title` is observable, and has get/set accessors.
64201 *
64202 * @constructor
64203 * @extends {ol.layer.Layer}
64204 * @fires ol.render.Event
64205 * @param {olx.layer.VectorOptions=} opt_options Options.
64206 * @api
64207 */
64208ol.layer.Vector = function(opt_options) {
64209 var options = opt_options ?
64210 opt_options : /** @type {olx.layer.VectorOptions} */ ({});
64211
64212 var baseOptions = ol.obj.assign({}, options);
64213
64214 delete baseOptions.style;
64215 delete baseOptions.renderBuffer;
64216 delete baseOptions.updateWhileAnimating;
64217 delete baseOptions.updateWhileInteracting;
64218 ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
64219
64220 /**
64221 * @type {number}
64222 * @private
64223 */
64224 this.renderBuffer_ = options.renderBuffer !== undefined ?
64225 options.renderBuffer : 100;
64226
64227 /**
64228 * User provided style.
64229 * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
64230 * @private
64231 */
64232 this.style_ = null;
64233
64234 /**
64235 * Style function for use within the library.
64236 * @type {ol.StyleFunction|undefined}
64237 * @private
64238 */
64239 this.styleFunction_ = undefined;
64240
64241 this.setStyle(options.style);
64242
64243 /**
64244 * @type {boolean}
64245 * @private
64246 */
64247 this.updateWhileAnimating_ = options.updateWhileAnimating !== undefined ?
64248 options.updateWhileAnimating : false;
64249
64250 /**
64251 * @type {boolean}
64252 * @private
64253 */
64254 this.updateWhileInteracting_ = options.updateWhileInteracting !== undefined ?
64255 options.updateWhileInteracting : false;
64256};
64257ol.inherits(ol.layer.Vector, ol.layer.Layer);
64258
64259
64260/**
64261 * @inheritDoc
64262 */
64263ol.layer.Vector.prototype.createRenderer = function(mapRenderer) {
64264 var renderer = null;
64265 var type = mapRenderer.getType();
64266 if (ol.ENABLE_CANVAS && type === ol.renderer.Type.CANVAS) {
64267 renderer = new ol.renderer.canvas.VectorLayer(this);
64268 } else if (ol.ENABLE_WEBGL && type === ol.renderer.Type.WEBGL) {
64269 renderer = new ol.renderer.webgl.VectorLayer(/** @type {ol.renderer.webgl.Map} */ (mapRenderer), this);
64270 }
64271 return renderer;
64272};
64273
64274
64275/**
64276 * @return {number|undefined} Render buffer.
64277 */
64278ol.layer.Vector.prototype.getRenderBuffer = function() {
64279 return this.renderBuffer_;
64280};
64281
64282
64283/**
64284 * @return {function(ol.Feature, ol.Feature): number|null|undefined} Render
64285 * order.
64286 */
64287ol.layer.Vector.prototype.getRenderOrder = function() {
64288 return /** @type {ol.RenderOrderFunction|null|undefined} */ (
64289 this.get(ol.layer.Vector.Property_.RENDER_ORDER));
64290};
64291
64292
64293/**
64294 * Return the associated {@link ol.source.Vector vectorsource} of the layer.
64295 * @function
64296 * @return {ol.source.Vector} Source.
64297 * @api
64298 */
64299ol.layer.Vector.prototype.getSource;
64300
64301
64302/**
64303 * Get the style for features. This returns whatever was passed to the `style`
64304 * option at construction or to the `setStyle` method.
64305 * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
64306 * Layer style.
64307 * @api
64308 */
64309ol.layer.Vector.prototype.getStyle = function() {
64310 return this.style_;
64311};
64312
64313
64314/**
64315 * Get the style function.
64316 * @return {ol.StyleFunction|undefined} Layer style function.
64317 * @api
64318 */
64319ol.layer.Vector.prototype.getStyleFunction = function() {
64320 return this.styleFunction_;
64321};
64322
64323
64324/**
64325 * @return {boolean} Whether the rendered layer should be updated while
64326 * animating.
64327 */
64328ol.layer.Vector.prototype.getUpdateWhileAnimating = function() {
64329 return this.updateWhileAnimating_;
64330};
64331
64332
64333/**
64334 * @return {boolean} Whether the rendered layer should be updated while
64335 * interacting.
64336 */
64337ol.layer.Vector.prototype.getUpdateWhileInteracting = function() {
64338 return this.updateWhileInteracting_;
64339};
64340
64341
64342/**
64343 * @param {ol.RenderOrderFunction|null|undefined} renderOrder
64344 * Render order.
64345 */
64346ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) {
64347 this.set(ol.layer.Vector.Property_.RENDER_ORDER, renderOrder);
64348};
64349
64350
64351/**
64352 * Set the style for features. This can be a single style object, an array
64353 * of styles, or a function that takes a feature and resolution and returns
64354 * an array of styles. If it is `undefined` the default style is used. If
64355 * it is `null` the layer has no style (a `null` style), so only features
64356 * that have their own styles will be rendered in the layer. See
64357 * {@link ol.style} for information on the default style.
64358 * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|null|undefined}
64359 * style Layer style.
64360 * @api
64361 */
64362ol.layer.Vector.prototype.setStyle = function(style) {
64363 this.style_ = style !== undefined ? style : ol.style.Style.defaultFunction;
64364 this.styleFunction_ = style === null ?
64365 undefined : ol.style.Style.createFunction(this.style_);
64366 this.changed();
64367};
64368
64369
64370/**
64371 * @enum {string}
64372 * @private
64373 */
64374ol.layer.Vector.Property_ = {
64375 RENDER_ORDER: 'renderOrder'
64376};
64377
64378goog.provide('ol.loadingstrategy');
64379
64380
64381/**
64382 * Strategy function for loading all features with a single request.
64383 * @param {ol.Extent} extent Extent.
64384 * @param {number} resolution Resolution.
64385 * @return {Array.<ol.Extent>} Extents.
64386 * @api
64387 */
64388ol.loadingstrategy.all = function(extent, resolution) {
64389 return [[-Infinity, -Infinity, Infinity, Infinity]];
64390};
64391
64392
64393/**
64394 * Strategy function for loading features based on the view's extent and
64395 * resolution.
64396 * @param {ol.Extent} extent Extent.
64397 * @param {number} resolution Resolution.
64398 * @return {Array.<ol.Extent>} Extents.
64399 * @api
64400 */
64401ol.loadingstrategy.bbox = function(extent, resolution) {
64402 return [extent];
64403};
64404
64405
64406/**
64407 * Creates a strategy function for loading features based on a tile grid.
64408 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
64409 * @return {function(ol.Extent, number): Array.<ol.Extent>} Loading strategy.
64410 * @api
64411 */
64412ol.loadingstrategy.tile = function(tileGrid) {
64413 return (
64414 /**
64415 * @param {ol.Extent} extent Extent.
64416 * @param {number} resolution Resolution.
64417 * @return {Array.<ol.Extent>} Extents.
64418 */
64419 function(extent, resolution) {
64420 var z = tileGrid.getZForResolution(resolution);
64421 var tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
64422 /** @type {Array.<ol.Extent>} */
64423 var extents = [];
64424 /** @type {ol.TileCoord} */
64425 var tileCoord = [z, 0, 0];
64426 for (tileCoord[1] = tileRange.minX; tileCoord[1] <= tileRange.maxX;
64427 ++tileCoord[1]) {
64428 for (tileCoord[2] = tileRange.minY; tileCoord[2] <= tileRange.maxY;
64429 ++tileCoord[2]) {
64430 extents.push(tileGrid.getTileCoordExtent(tileCoord));
64431 }
64432 }
64433 return extents;
64434 });
64435};
64436
64437goog.provide('ol.source.Source');
64438
64439goog.require('ol');
64440goog.require('ol.Attribution');
64441goog.require('ol.Object');
64442goog.require('ol.proj');
64443goog.require('ol.source.State');
64444
64445
64446/**
64447 * @classdesc
64448 * Abstract base class; normally only used for creating subclasses and not
64449 * instantiated in apps.
64450 * Base class for {@link ol.layer.Layer} sources.
64451 *
64452 * A generic `change` event is triggered when the state of the source changes.
64453 *
64454 * @constructor
64455 * @abstract
64456 * @extends {ol.Object}
64457 * @param {ol.SourceSourceOptions} options Source options.
64458 * @api
64459 */
64460ol.source.Source = function(options) {
64461
64462 ol.Object.call(this);
64463
64464 /**
64465 * @private
64466 * @type {ol.proj.Projection}
64467 */
64468 this.projection_ = ol.proj.get(options.projection);
64469
64470 /**
64471 * @private
64472 * @type {Array.<ol.Attribution>}
64473 */
64474 this.attributions_ = ol.source.Source.toAttributionsArray_(options.attributions);
64475
64476 /**
64477 * @private
64478 * @type {string|olx.LogoOptions|undefined}
64479 */
64480 this.logo_ = options.logo;
64481
64482 /**
64483 * @private
64484 * @type {ol.source.State}
64485 */
64486 this.state_ = options.state !== undefined ?
64487 options.state : ol.source.State.READY;
64488
64489 /**
64490 * @private
64491 * @type {boolean}
64492 */
64493 this.wrapX_ = options.wrapX !== undefined ? options.wrapX : false;
64494
64495};
64496ol.inherits(ol.source.Source, ol.Object);
64497
64498/**
64499 * Turns various ways of defining an attribution to an array of `ol.Attributions`.
64500 *
64501 * @param {ol.AttributionLike|undefined}
64502 * attributionLike The attributions as string, array of strings,
64503 * `ol.Attribution`, array of `ol.Attribution` or undefined.
64504 * @return {Array.<ol.Attribution>} The array of `ol.Attribution` or null if
64505 * `undefined` was given.
64506 */
64507ol.source.Source.toAttributionsArray_ = function(attributionLike) {
64508 if (typeof attributionLike === 'string') {
64509 return [new ol.Attribution({html: attributionLike})];
64510 } else if (attributionLike instanceof ol.Attribution) {
64511 return [attributionLike];
64512 } else if (Array.isArray(attributionLike)) {
64513 var len = attributionLike.length;
64514 var attributions = new Array(len);
64515 for (var i = 0; i < len; i++) {
64516 var item = attributionLike[i];
64517 if (typeof item === 'string') {
64518 attributions[i] = new ol.Attribution({html: item});
64519 } else {
64520 attributions[i] = item;
64521 }
64522 }
64523 return attributions;
64524 } else {
64525 return null;
64526 }
64527};
64528
64529
64530/**
64531 * @param {ol.Coordinate} coordinate Coordinate.
64532 * @param {number} resolution Resolution.
64533 * @param {number} rotation Rotation.
64534 * @param {number} hitTolerance Hit tolerance in pixels.
64535 * @param {Object.<string, boolean>} skippedFeatureUids Skipped feature uids.
64536 * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature
64537 * callback.
64538 * @return {T|undefined} Callback result.
64539 * @template T
64540 */
64541ol.source.Source.prototype.forEachFeatureAtCoordinate = ol.nullFunction;
64542
64543
64544/**
64545 * Get the attributions of the source.
64546 * @return {Array.<ol.Attribution>} Attributions.
64547 * @api
64548 */
64549ol.source.Source.prototype.getAttributions = function() {
64550 return this.attributions_;
64551};
64552
64553
64554/**
64555 * Get the logo of the source.
64556 * @return {string|olx.LogoOptions|undefined} Logo.
64557 * @api
64558 */
64559ol.source.Source.prototype.getLogo = function() {
64560 return this.logo_;
64561};
64562
64563
64564/**
64565 * Get the projection of the source.
64566 * @return {ol.proj.Projection} Projection.
64567 * @api
64568 */
64569ol.source.Source.prototype.getProjection = function() {
64570 return this.projection_;
64571};
64572
64573
64574/**
64575 * @abstract
64576 * @return {Array.<number>|undefined} Resolutions.
64577 */
64578ol.source.Source.prototype.getResolutions = function() {};
64579
64580
64581/**
64582 * Get the state of the source, see {@link ol.source.State} for possible states.
64583 * @return {ol.source.State} State.
64584 * @api
64585 */
64586ol.source.Source.prototype.getState = function() {
64587 return this.state_;
64588};
64589
64590
64591/**
64592 * @return {boolean|undefined} Wrap X.
64593 */
64594ol.source.Source.prototype.getWrapX = function() {
64595 return this.wrapX_;
64596};
64597
64598
64599/**
64600 * Refreshes the source and finally dispatches a 'change' event.
64601 * @api
64602 */
64603ol.source.Source.prototype.refresh = function() {
64604 this.changed();
64605};
64606
64607
64608/**
64609 * Set the attributions of the source.
64610 * @param {ol.AttributionLike|undefined} attributions Attributions.
64611 * Can be passed as `string`, `Array<string>`, `{@link ol.Attribution}`,
64612 * `Array<{@link ol.Attribution}>` or `undefined`.
64613 * @api
64614 */
64615ol.source.Source.prototype.setAttributions = function(attributions) {
64616 this.attributions_ = ol.source.Source.toAttributionsArray_(attributions);
64617 this.changed();
64618};
64619
64620
64621/**
64622 * Set the logo of the source.
64623 * @param {string|olx.LogoOptions|undefined} logo Logo.
64624 */
64625ol.source.Source.prototype.setLogo = function(logo) {
64626 this.logo_ = logo;
64627};
64628
64629
64630/**
64631 * Set the state of the source.
64632 * @param {ol.source.State} state State.
64633 * @protected
64634 */
64635ol.source.Source.prototype.setState = function(state) {
64636 this.state_ = state;
64637 this.changed();
64638};
64639
64640goog.provide('ol.source.VectorEventType');
64641
64642/**
64643 * @enum {string}
64644 */
64645ol.source.VectorEventType = {
64646 /**
64647 * Triggered when a feature is added to the source.
64648 * @event ol.source.Vector.Event#addfeature
64649 * @api
64650 */
64651 ADDFEATURE: 'addfeature',
64652
64653 /**
64654 * Triggered when a feature is updated.
64655 * @event ol.source.Vector.Event#changefeature
64656 * @api
64657 */
64658 CHANGEFEATURE: 'changefeature',
64659
64660 /**
64661 * Triggered when the clear method is called on the source.
64662 * @event ol.source.Vector.Event#clear
64663 * @api
64664 */
64665 CLEAR: 'clear',
64666
64667 /**
64668 * Triggered when a feature is removed from the source.
64669 * See {@link ol.source.Vector#clear source.clear()} for exceptions.
64670 * @event ol.source.Vector.Event#removefeature
64671 * @api
64672 */
64673 REMOVEFEATURE: 'removefeature'
64674};
64675
64676// FIXME bulk feature upload - suppress events
64677// FIXME make change-detection more refined (notably, geometry hint)
64678
64679goog.provide('ol.source.Vector');
64680
64681goog.require('ol');
64682goog.require('ol.Collection');
64683goog.require('ol.CollectionEventType');
64684goog.require('ol.ObjectEventType');
64685goog.require('ol.array');
64686goog.require('ol.asserts');
64687goog.require('ol.events');
64688goog.require('ol.events.Event');
64689goog.require('ol.events.EventType');
64690goog.require('ol.extent');
64691goog.require('ol.featureloader');
64692goog.require('ol.functions');
64693goog.require('ol.loadingstrategy');
64694goog.require('ol.obj');
64695goog.require('ol.source.Source');
64696goog.require('ol.source.State');
64697goog.require('ol.source.VectorEventType');
64698goog.require('ol.structs.RBush');
64699
64700
64701/**
64702 * @classdesc
64703 * Provides a source of features for vector layers. Vector features provided
64704 * by this source are suitable for editing. See {@link ol.source.VectorTile} for
64705 * vector data that is optimized for rendering.
64706 *
64707 * @constructor
64708 * @extends {ol.source.Source}
64709 * @fires ol.source.Vector.Event
64710 * @param {olx.source.VectorOptions=} opt_options Vector source options.
64711 * @api
64712 */
64713ol.source.Vector = function(opt_options) {
64714
64715 var options = opt_options || {};
64716
64717 ol.source.Source.call(this, {
64718 attributions: options.attributions,
64719 logo: options.logo,
64720 projection: undefined,
64721 state: ol.source.State.READY,
64722 wrapX: options.wrapX !== undefined ? options.wrapX : true
64723 });
64724
64725 /**
64726 * @private
64727 * @type {ol.FeatureLoader}
64728 */
64729 this.loader_ = ol.nullFunction;
64730
64731 /**
64732 * @private
64733 * @type {ol.format.Feature|undefined}
64734 */
64735 this.format_ = options.format;
64736
64737 /**
64738 * @private
64739 * @type {boolean}
64740 */
64741 this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;
64742
64743 /**
64744 * @private
64745 * @type {string|ol.FeatureUrlFunction|undefined}
64746 */
64747 this.url_ = options.url;
64748
64749 if (options.loader !== undefined) {
64750 this.loader_ = options.loader;
64751 } else if (this.url_ !== undefined) {
64752 ol.asserts.assert(this.format_, 7); // `format` must be set when `url` is set
64753 // create a XHR feature loader for "url" and "format"
64754 this.loader_ = ol.featureloader.xhr(this.url_, /** @type {ol.format.Feature} */ (this.format_));
64755 }
64756
64757 /**
64758 * @private
64759 * @type {ol.LoadingStrategy}
64760 */
64761 this.strategy_ = options.strategy !== undefined ? options.strategy :
64762 ol.loadingstrategy.all;
64763
64764 var useSpatialIndex =
64765 options.useSpatialIndex !== undefined ? options.useSpatialIndex : true;
64766
64767 /**
64768 * @private
64769 * @type {ol.structs.RBush.<ol.Feature>}
64770 */
64771 this.featuresRtree_ = useSpatialIndex ? new ol.structs.RBush() : null;
64772
64773 /**
64774 * @private
64775 * @type {ol.structs.RBush.<{extent: ol.Extent}>}
64776 */
64777 this.loadedExtentsRtree_ = new ol.structs.RBush();
64778
64779 /**
64780 * @private
64781 * @type {Object.<string, ol.Feature>}
64782 */
64783 this.nullGeometryFeatures_ = {};
64784
64785 /**
64786 * A lookup of features by id (the return from feature.getId()).
64787 * @private
64788 * @type {Object.<string, ol.Feature>}
64789 */
64790 this.idIndex_ = {};
64791
64792 /**
64793 * A lookup of features without id (keyed by ol.getUid(feature)).
64794 * @private
64795 * @type {Object.<string, ol.Feature>}
64796 */
64797 this.undefIdIndex_ = {};
64798
64799 /**
64800 * @private
64801 * @type {Object.<string, Array.<ol.EventsKey>>}
64802 */
64803 this.featureChangeKeys_ = {};
64804
64805 /**
64806 * @private
64807 * @type {ol.Collection.<ol.Feature>}
64808 */
64809 this.featuresCollection_ = null;
64810
64811 var collection, features;
64812 if (options.features instanceof ol.Collection) {
64813 collection = options.features;
64814 features = collection.getArray();
64815 } else if (Array.isArray(options.features)) {
64816 features = options.features;
64817 }
64818 if (!useSpatialIndex && collection === undefined) {
64819 collection = new ol.Collection(features);
64820 }
64821 if (features !== undefined) {
64822 this.addFeaturesInternal(features);
64823 }
64824 if (collection !== undefined) {
64825 this.bindFeaturesCollection_(collection);
64826 }
64827
64828};
64829ol.inherits(ol.source.Vector, ol.source.Source);
64830
64831
64832/**
64833 * Add a single feature to the source. If you want to add a batch of features
64834 * at once, call {@link ol.source.Vector#addFeatures source.addFeatures()}
64835 * instead. A feature will not be added to the source if feature with
64836 * the same id is already there. The reason for this behavior is to avoid
64837 * feature duplication when using bbox or tile loading strategies.
64838 * @param {ol.Feature} feature Feature to add.
64839 * @api
64840 */
64841ol.source.Vector.prototype.addFeature = function(feature) {
64842 this.addFeatureInternal(feature);
64843 this.changed();
64844};
64845
64846
64847/**
64848 * Add a feature without firing a `change` event.
64849 * @param {ol.Feature} feature Feature.
64850 * @protected
64851 */
64852ol.source.Vector.prototype.addFeatureInternal = function(feature) {
64853 var featureKey = ol.getUid(feature).toString();
64854
64855 if (!this.addToIndex_(featureKey, feature)) {
64856 return;
64857 }
64858
64859 this.setupChangeEvents_(featureKey, feature);
64860
64861 var geometry = feature.getGeometry();
64862 if (geometry) {
64863 var extent = geometry.getExtent();
64864 if (this.featuresRtree_) {
64865 this.featuresRtree_.insert(extent, feature);
64866 }
64867 } else {
64868 this.nullGeometryFeatures_[featureKey] = feature;
64869 }
64870
64871 this.dispatchEvent(
64872 new ol.source.Vector.Event(ol.source.VectorEventType.ADDFEATURE, feature));
64873};
64874
64875
64876/**
64877 * @param {string} featureKey Unique identifier for the feature.
64878 * @param {ol.Feature} feature The feature.
64879 * @private
64880 */
64881ol.source.Vector.prototype.setupChangeEvents_ = function(featureKey, feature) {
64882 this.featureChangeKeys_[featureKey] = [
64883 ol.events.listen(feature, ol.events.EventType.CHANGE,
64884 this.handleFeatureChange_, this),
64885 ol.events.listen(feature, ol.ObjectEventType.PROPERTYCHANGE,
64886 this.handleFeatureChange_, this)
64887 ];
64888};
64889
64890
64891/**
64892 * @param {string} featureKey Unique identifier for the feature.
64893 * @param {ol.Feature} feature The feature.
64894 * @return {boolean} The feature is "valid", in the sense that it is also a
64895 * candidate for insertion into the Rtree.
64896 * @private
64897 */
64898ol.source.Vector.prototype.addToIndex_ = function(featureKey, feature) {
64899 var valid = true;
64900 var id = feature.getId();
64901 if (id !== undefined) {
64902 if (!(id.toString() in this.idIndex_)) {
64903 this.idIndex_[id.toString()] = feature;
64904 } else {
64905 valid = false;
64906 }
64907 } else {
64908 ol.asserts.assert(!(featureKey in this.undefIdIndex_),
64909 30); // The passed `feature` was already added to the source
64910 this.undefIdIndex_[featureKey] = feature;
64911 }
64912 return valid;
64913};
64914
64915
64916/**
64917 * Add a batch of features to the source.
64918 * @param {Array.<ol.Feature>} features Features to add.
64919 * @api
64920 */
64921ol.source.Vector.prototype.addFeatures = function(features) {
64922 this.addFeaturesInternal(features);
64923 this.changed();
64924};
64925
64926
64927/**
64928 * Add features without firing a `change` event.
64929 * @param {Array.<ol.Feature>} features Features.
64930 * @protected
64931 */
64932ol.source.Vector.prototype.addFeaturesInternal = function(features) {
64933 var featureKey, i, length, feature;
64934
64935 var extents = [];
64936 var newFeatures = [];
64937 var geometryFeatures = [];
64938
64939 for (i = 0, length = features.length; i < length; i++) {
64940 feature = features[i];
64941 featureKey = ol.getUid(feature).toString();
64942 if (this.addToIndex_(featureKey, feature)) {
64943 newFeatures.push(feature);
64944 }
64945 }
64946
64947 for (i = 0, length = newFeatures.length; i < length; i++) {
64948 feature = newFeatures[i];
64949 featureKey = ol.getUid(feature).toString();
64950 this.setupChangeEvents_(featureKey, feature);
64951
64952 var geometry = feature.getGeometry();
64953 if (geometry) {
64954 var extent = geometry.getExtent();
64955 extents.push(extent);
64956 geometryFeatures.push(feature);
64957 } else {
64958 this.nullGeometryFeatures_[featureKey] = feature;
64959 }
64960 }
64961 if (this.featuresRtree_) {
64962 this.featuresRtree_.load(extents, geometryFeatures);
64963 }
64964
64965 for (i = 0, length = newFeatures.length; i < length; i++) {
64966 this.dispatchEvent(new ol.source.Vector.Event(
64967 ol.source.VectorEventType.ADDFEATURE, newFeatures[i]));
64968 }
64969};
64970
64971
64972/**
64973 * @param {!ol.Collection.<ol.Feature>} collection Collection.
64974 * @private
64975 */
64976ol.source.Vector.prototype.bindFeaturesCollection_ = function(collection) {
64977 var modifyingCollection = false;
64978 ol.events.listen(this, ol.source.VectorEventType.ADDFEATURE,
64979 function(evt) {
64980 if (!modifyingCollection) {
64981 modifyingCollection = true;
64982 collection.push(evt.feature);
64983 modifyingCollection = false;
64984 }
64985 });
64986 ol.events.listen(this, ol.source.VectorEventType.REMOVEFEATURE,
64987 function(evt) {
64988 if (!modifyingCollection) {
64989 modifyingCollection = true;
64990 collection.remove(evt.feature);
64991 modifyingCollection = false;
64992 }
64993 });
64994 ol.events.listen(collection, ol.CollectionEventType.ADD,
64995 function(evt) {
64996 if (!modifyingCollection) {
64997 modifyingCollection = true;
64998 this.addFeature(/** @type {ol.Feature} */ (evt.element));
64999 modifyingCollection = false;
65000 }
65001 }, this);
65002 ol.events.listen(collection, ol.CollectionEventType.REMOVE,
65003 function(evt) {
65004 if (!modifyingCollection) {
65005 modifyingCollection = true;
65006 this.removeFeature(/** @type {ol.Feature} */ (evt.element));
65007 modifyingCollection = false;
65008 }
65009 }, this);
65010 this.featuresCollection_ = collection;
65011};
65012
65013
65014/**
65015 * Remove all features from the source.
65016 * @param {boolean=} opt_fast Skip dispatching of {@link removefeature} events.
65017 * @api
65018 */
65019ol.source.Vector.prototype.clear = function(opt_fast) {
65020 if (opt_fast) {
65021 for (var featureId in this.featureChangeKeys_) {
65022 var keys = this.featureChangeKeys_[featureId];
65023 keys.forEach(ol.events.unlistenByKey);
65024 }
65025 if (!this.featuresCollection_) {
65026 this.featureChangeKeys_ = {};
65027 this.idIndex_ = {};
65028 this.undefIdIndex_ = {};
65029 }
65030 } else {
65031 if (this.featuresRtree_) {
65032 this.featuresRtree_.forEach(this.removeFeatureInternal, this);
65033 for (var id in this.nullGeometryFeatures_) {
65034 this.removeFeatureInternal(this.nullGeometryFeatures_[id]);
65035 }
65036 }
65037 }
65038 if (this.featuresCollection_) {
65039 this.featuresCollection_.clear();
65040 }
65041
65042 if (this.featuresRtree_) {
65043 this.featuresRtree_.clear();
65044 }
65045 this.loadedExtentsRtree_.clear();
65046 this.nullGeometryFeatures_ = {};
65047
65048 var clearEvent = new ol.source.Vector.Event(ol.source.VectorEventType.CLEAR);
65049 this.dispatchEvent(clearEvent);
65050 this.changed();
65051};
65052
65053
65054/**
65055 * Iterate through all features on the source, calling the provided callback
65056 * with each one. If the callback returns any "truthy" value, iteration will
65057 * stop and the function will return the same value.
65058 *
65059 * @param {function(this: T, ol.Feature): S} callback Called with each feature
65060 * on the source. Return a truthy value to stop iteration.
65061 * @param {T=} opt_this The object to use as `this` in the callback.
65062 * @return {S|undefined} The return value from the last call to the callback.
65063 * @template T,S
65064 * @api
65065 */
65066ol.source.Vector.prototype.forEachFeature = function(callback, opt_this) {
65067 if (this.featuresRtree_) {
65068 return this.featuresRtree_.forEach(callback, opt_this);
65069 } else if (this.featuresCollection_) {
65070 return this.featuresCollection_.forEach(callback, opt_this);
65071 }
65072};
65073
65074
65075/**
65076 * Iterate through all features whose geometries contain the provided
65077 * coordinate, calling the callback with each feature. If the callback returns
65078 * a "truthy" value, iteration will stop and the function will return the same
65079 * value.
65080 *
65081 * @param {ol.Coordinate} coordinate Coordinate.
65082 * @param {function(this: T, ol.Feature): S} callback Called with each feature
65083 * whose goemetry contains the provided coordinate.
65084 * @param {T=} opt_this The object to use as `this` in the callback.
65085 * @return {S|undefined} The return value from the last call to the callback.
65086 * @template T,S
65087 */
65088ol.source.Vector.prototype.forEachFeatureAtCoordinateDirect = function(coordinate, callback, opt_this) {
65089 var extent = [coordinate[0], coordinate[1], coordinate[0], coordinate[1]];
65090 return this.forEachFeatureInExtent(extent, function(feature) {
65091 var geometry = feature.getGeometry();
65092 if (geometry.intersectsCoordinate(coordinate)) {
65093 return callback.call(opt_this, feature);
65094 } else {
65095 return undefined;
65096 }
65097 });
65098};
65099
65100
65101/**
65102 * Iterate through all features whose bounding box intersects the provided
65103 * extent (note that the feature's geometry may not intersect the extent),
65104 * calling the callback with each feature. If the callback returns a "truthy"
65105 * value, iteration will stop and the function will return the same value.
65106 *
65107 * If you are interested in features whose geometry intersects an extent, call
65108 * the {@link ol.source.Vector#forEachFeatureIntersectingExtent
65109 * source.forEachFeatureIntersectingExtent()} method instead.
65110 *
65111 * When `useSpatialIndex` is set to false, this method will loop through all
65112 * features, equivalent to {@link ol.source.Vector#forEachFeature}.
65113 *
65114 * @param {ol.Extent} extent Extent.
65115 * @param {function(this: T, ol.Feature): S} callback Called with each feature
65116 * whose bounding box intersects the provided extent.
65117 * @param {T=} opt_this The object to use as `this` in the callback.
65118 * @return {S|undefined} The return value from the last call to the callback.
65119 * @template T,S
65120 * @api
65121 */
65122ol.source.Vector.prototype.forEachFeatureInExtent = function(extent, callback, opt_this) {
65123 if (this.featuresRtree_) {
65124 return this.featuresRtree_.forEachInExtent(extent, callback, opt_this);
65125 } else if (this.featuresCollection_) {
65126 return this.featuresCollection_.forEach(callback, opt_this);
65127 }
65128};
65129
65130
65131/**
65132 * Iterate through all features whose geometry intersects the provided extent,
65133 * calling the callback with each feature. If the callback returns a "truthy"
65134 * value, iteration will stop and the function will return the same value.
65135 *
65136 * If you only want to test for bounding box intersection, call the
65137 * {@link ol.source.Vector#forEachFeatureInExtent
65138 * source.forEachFeatureInExtent()} method instead.
65139 *
65140 * @param {ol.Extent} extent Extent.
65141 * @param {function(this: T, ol.Feature): S} callback Called with each feature
65142 * whose geometry intersects the provided extent.
65143 * @param {T=} opt_this The object to use as `this` in the callback.
65144 * @return {S|undefined} The return value from the last call to the callback.
65145 * @template T,S
65146 * @api
65147 */
65148ol.source.Vector.prototype.forEachFeatureIntersectingExtent = function(extent, callback, opt_this) {
65149 return this.forEachFeatureInExtent(extent,
65150 /**
65151 * @param {ol.Feature} feature Feature.
65152 * @return {S|undefined} The return value from the last call to the callback.
65153 * @template S
65154 */
65155 function(feature) {
65156 var geometry = feature.getGeometry();
65157 if (geometry.intersectsExtent(extent)) {
65158 var result = callback.call(opt_this, feature);
65159 if (result) {
65160 return result;
65161 }
65162 }
65163 });
65164};
65165
65166
65167/**
65168 * Get the features collection associated with this source. Will be `null`
65169 * unless the source was configured with `useSpatialIndex` set to `false`, or
65170 * with an {@link ol.Collection} as `features`.
65171 * @return {ol.Collection.<ol.Feature>} The collection of features.
65172 * @api
65173 */
65174ol.source.Vector.prototype.getFeaturesCollection = function() {
65175 return this.featuresCollection_;
65176};
65177
65178
65179/**
65180 * Get all features on the source in random order.
65181 * @return {Array.<ol.Feature>} Features.
65182 * @api
65183 */
65184ol.source.Vector.prototype.getFeatures = function() {
65185 var features;
65186 if (this.featuresCollection_) {
65187 features = this.featuresCollection_.getArray();
65188 } else if (this.featuresRtree_) {
65189 features = this.featuresRtree_.getAll();
65190 if (!ol.obj.isEmpty(this.nullGeometryFeatures_)) {
65191 ol.array.extend(
65192 features, ol.obj.getValues(this.nullGeometryFeatures_));
65193 }
65194 }
65195 return /** @type {Array.<ol.Feature>} */ (features);
65196};
65197
65198
65199/**
65200 * Get all features whose geometry intersects the provided coordinate.
65201 * @param {ol.Coordinate} coordinate Coordinate.
65202 * @return {Array.<ol.Feature>} Features.
65203 * @api
65204 */
65205ol.source.Vector.prototype.getFeaturesAtCoordinate = function(coordinate) {
65206 var features = [];
65207 this.forEachFeatureAtCoordinateDirect(coordinate, function(feature) {
65208 features.push(feature);
65209 });
65210 return features;
65211};
65212
65213
65214/**
65215 * Get all features in the provided extent. Note that this returns an array of
65216 * all features intersecting the given extent in random order (so it may include
65217 * features whose geometries do not intersect the extent).
65218 *
65219 * This method is not available when the source is configured with
65220 * `useSpatialIndex` set to `false`.
65221 * @param {ol.Extent} extent Extent.
65222 * @return {Array.<ol.Feature>} Features.
65223 * @api
65224 */
65225ol.source.Vector.prototype.getFeaturesInExtent = function(extent) {
65226 return this.featuresRtree_.getInExtent(extent);
65227};
65228
65229
65230/**
65231 * Get the closest feature to the provided coordinate.
65232 *
65233 * This method is not available when the source is configured with
65234 * `useSpatialIndex` set to `false`.
65235 * @param {ol.Coordinate} coordinate Coordinate.
65236 * @param {function(ol.Feature):boolean=} opt_filter Feature filter function.
65237 * The filter function will receive one argument, the {@link ol.Feature feature}
65238 * and it should return a boolean value. By default, no filtering is made.
65239 * @return {ol.Feature} Closest feature.
65240 * @api
65241 */
65242ol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate, opt_filter) {
65243 // Find the closest feature using branch and bound. We start searching an
65244 // infinite extent, and find the distance from the first feature found. This
65245 // becomes the closest feature. We then compute a smaller extent which any
65246 // closer feature must intersect. We continue searching with this smaller
65247 // extent, trying to find a closer feature. Every time we find a closer
65248 // feature, we update the extent being searched so that any even closer
65249 // feature must intersect it. We continue until we run out of features.
65250 var x = coordinate[0];
65251 var y = coordinate[1];
65252 var closestFeature = null;
65253 var closestPoint = [NaN, NaN];
65254 var minSquaredDistance = Infinity;
65255 var extent = [-Infinity, -Infinity, Infinity, Infinity];
65256 var filter = opt_filter ? opt_filter : ol.functions.TRUE;
65257 this.featuresRtree_.forEachInExtent(extent,
65258 /**
65259 * @param {ol.Feature} feature Feature.
65260 */
65261 function(feature) {
65262 if (filter(feature)) {
65263 var geometry = feature.getGeometry();
65264 var previousMinSquaredDistance = minSquaredDistance;
65265 minSquaredDistance = geometry.closestPointXY(
65266 x, y, closestPoint, minSquaredDistance);
65267 if (minSquaredDistance < previousMinSquaredDistance) {
65268 closestFeature = feature;
65269 // This is sneaky. Reduce the extent that it is currently being
65270 // searched while the R-Tree traversal using this same extent object
65271 // is still in progress. This is safe because the new extent is
65272 // strictly contained by the old extent.
65273 var minDistance = Math.sqrt(minSquaredDistance);
65274 extent[0] = x - minDistance;
65275 extent[1] = y - minDistance;
65276 extent[2] = x + minDistance;
65277 extent[3] = y + minDistance;
65278 }
65279 }
65280 });
65281 return closestFeature;
65282};
65283
65284
65285/**
65286 * Get the extent of the features currently in the source.
65287 *
65288 * This method is not available when the source is configured with
65289 * `useSpatialIndex` set to `false`.
65290 * @param {ol.Extent=} opt_extent Destination extent. If provided, no new extent
65291 * will be created. Instead, that extent's coordinates will be overwritten.
65292 * @return {ol.Extent} Extent.
65293 * @api
65294 */
65295ol.source.Vector.prototype.getExtent = function(opt_extent) {
65296 return this.featuresRtree_.getExtent(opt_extent);
65297};
65298
65299
65300/**
65301 * Get a feature by its identifier (the value returned by feature.getId()).
65302 * Note that the index treats string and numeric identifiers as the same. So
65303 * `source.getFeatureById(2)` will return a feature with id `'2'` or `2`.
65304 *
65305 * @param {string|number} id Feature identifier.
65306 * @return {ol.Feature} The feature (or `null` if not found).
65307 * @api
65308 */
65309ol.source.Vector.prototype.getFeatureById = function(id) {
65310 var feature = this.idIndex_[id.toString()];
65311 return feature !== undefined ? feature : null;
65312};
65313
65314
65315/**
65316 * Get the format associated with this source.
65317 *
65318 * @return {ol.format.Feature|undefined} The feature format.
65319 * @api
65320 */
65321ol.source.Vector.prototype.getFormat = function() {
65322 return this.format_;
65323};
65324
65325
65326/**
65327 * @return {boolean} The source can have overlapping geometries.
65328 */
65329ol.source.Vector.prototype.getOverlaps = function() {
65330 return this.overlaps_;
65331};
65332
65333
65334/**
65335 * @override
65336 */
65337ol.source.Vector.prototype.getResolutions = function() {};
65338
65339
65340/**
65341 * Get the url associated with this source.
65342 *
65343 * @return {string|ol.FeatureUrlFunction|undefined} The url.
65344 * @api
65345 */
65346ol.source.Vector.prototype.getUrl = function() {
65347 return this.url_;
65348};
65349
65350
65351/**
65352 * @param {ol.events.Event} event Event.
65353 * @private
65354 */
65355ol.source.Vector.prototype.handleFeatureChange_ = function(event) {
65356 var feature = /** @type {ol.Feature} */ (event.target);
65357 var featureKey = ol.getUid(feature).toString();
65358 var geometry = feature.getGeometry();
65359 if (!geometry) {
65360 if (!(featureKey in this.nullGeometryFeatures_)) {
65361 if (this.featuresRtree_) {
65362 this.featuresRtree_.remove(feature);
65363 }
65364 this.nullGeometryFeatures_[featureKey] = feature;
65365 }
65366 } else {
65367 var extent = geometry.getExtent();
65368 if (featureKey in this.nullGeometryFeatures_) {
65369 delete this.nullGeometryFeatures_[featureKey];
65370 if (this.featuresRtree_) {
65371 this.featuresRtree_.insert(extent, feature);
65372 }
65373 } else {
65374 if (this.featuresRtree_) {
65375 this.featuresRtree_.update(extent, feature);
65376 }
65377 }
65378 }
65379 var id = feature.getId();
65380 if (id !== undefined) {
65381 var sid = id.toString();
65382 if (featureKey in this.undefIdIndex_) {
65383 delete this.undefIdIndex_[featureKey];
65384 this.idIndex_[sid] = feature;
65385 } else {
65386 if (this.idIndex_[sid] !== feature) {
65387 this.removeFromIdIndex_(feature);
65388 this.idIndex_[sid] = feature;
65389 }
65390 }
65391 } else {
65392 if (!(featureKey in this.undefIdIndex_)) {
65393 this.removeFromIdIndex_(feature);
65394 this.undefIdIndex_[featureKey] = feature;
65395 }
65396 }
65397 this.changed();
65398 this.dispatchEvent(new ol.source.Vector.Event(
65399 ol.source.VectorEventType.CHANGEFEATURE, feature));
65400};
65401
65402
65403/**
65404 * @return {boolean} Is empty.
65405 */
65406ol.source.Vector.prototype.isEmpty = function() {
65407 return this.featuresRtree_.isEmpty() &&
65408 ol.obj.isEmpty(this.nullGeometryFeatures_);
65409};
65410
65411
65412/**
65413 * @param {ol.Extent} extent Extent.
65414 * @param {number} resolution Resolution.
65415 * @param {ol.proj.Projection} projection Projection.
65416 */
65417ol.source.Vector.prototype.loadFeatures = function(
65418 extent, resolution, projection) {
65419 var loadedExtentsRtree = this.loadedExtentsRtree_;
65420 var extentsToLoad = this.strategy_(extent, resolution);
65421 var i, ii;
65422 for (i = 0, ii = extentsToLoad.length; i < ii; ++i) {
65423 var extentToLoad = extentsToLoad[i];
65424 var alreadyLoaded = loadedExtentsRtree.forEachInExtent(extentToLoad,
65425 /**
65426 * @param {{extent: ol.Extent}} object Object.
65427 * @return {boolean} Contains.
65428 */
65429 function(object) {
65430 return ol.extent.containsExtent(object.extent, extentToLoad);
65431 });
65432 if (!alreadyLoaded) {
65433 this.loader_.call(this, extentToLoad, resolution, projection);
65434 loadedExtentsRtree.insert(extentToLoad, {extent: extentToLoad.slice()});
65435 }
65436 }
65437};
65438
65439
65440/**
65441 * Remove a single feature from the source. If you want to remove all features
65442 * at once, use the {@link ol.source.Vector#clear source.clear()} method
65443 * instead.
65444 * @param {ol.Feature} feature Feature to remove.
65445 * @api
65446 */
65447ol.source.Vector.prototype.removeFeature = function(feature) {
65448 var featureKey = ol.getUid(feature).toString();
65449 if (featureKey in this.nullGeometryFeatures_) {
65450 delete this.nullGeometryFeatures_[featureKey];
65451 } else {
65452 if (this.featuresRtree_) {
65453 this.featuresRtree_.remove(feature);
65454 }
65455 }
65456 this.removeFeatureInternal(feature);
65457 this.changed();
65458};
65459
65460
65461/**
65462 * Remove feature without firing a `change` event.
65463 * @param {ol.Feature} feature Feature.
65464 * @protected
65465 */
65466ol.source.Vector.prototype.removeFeatureInternal = function(feature) {
65467 var featureKey = ol.getUid(feature).toString();
65468 this.featureChangeKeys_[featureKey].forEach(ol.events.unlistenByKey);
65469 delete this.featureChangeKeys_[featureKey];
65470 var id = feature.getId();
65471 if (id !== undefined) {
65472 delete this.idIndex_[id.toString()];
65473 } else {
65474 delete this.undefIdIndex_[featureKey];
65475 }
65476 this.dispatchEvent(new ol.source.Vector.Event(
65477 ol.source.VectorEventType.REMOVEFEATURE, feature));
65478};
65479
65480
65481/**
65482 * Remove a feature from the id index. Called internally when the feature id
65483 * may have changed.
65484 * @param {ol.Feature} feature The feature.
65485 * @return {boolean} Removed the feature from the index.
65486 * @private
65487 */
65488ol.source.Vector.prototype.removeFromIdIndex_ = function(feature) {
65489 var removed = false;
65490 for (var id in this.idIndex_) {
65491 if (this.idIndex_[id] === feature) {
65492 delete this.idIndex_[id];
65493 removed = true;
65494 break;
65495 }
65496 }
65497 return removed;
65498};
65499
65500
65501/**
65502 * @classdesc
65503 * Events emitted by {@link ol.source.Vector} instances are instances of this
65504 * type.
65505 *
65506 * @constructor
65507 * @extends {ol.events.Event}
65508 * @implements {oli.source.Vector.Event}
65509 * @param {string} type Type.
65510 * @param {ol.Feature=} opt_feature Feature.
65511 */
65512ol.source.Vector.Event = function(type, opt_feature) {
65513
65514 ol.events.Event.call(this, type);
65515
65516 /**
65517 * The feature being added or removed.
65518 * @type {ol.Feature|undefined}
65519 * @api
65520 */
65521 this.feature = opt_feature;
65522
65523};
65524ol.inherits(ol.source.Vector.Event, ol.events.Event);
65525
65526goog.provide('ol.interaction.Draw');
65527
65528goog.require('ol');
65529goog.require('ol.Feature');
65530goog.require('ol.MapBrowserEventType');
65531goog.require('ol.Object');
65532goog.require('ol.coordinate');
65533goog.require('ol.events');
65534goog.require('ol.events.Event');
65535goog.require('ol.events.condition');
65536goog.require('ol.extent');
65537goog.require('ol.functions');
65538goog.require('ol.geom.Circle');
65539goog.require('ol.geom.GeometryType');
65540goog.require('ol.geom.LineString');
65541goog.require('ol.geom.MultiLineString');
65542goog.require('ol.geom.MultiPoint');
65543goog.require('ol.geom.MultiPolygon');
65544goog.require('ol.geom.Point');
65545goog.require('ol.geom.Polygon');
65546goog.require('ol.interaction.DrawEventType');
65547goog.require('ol.interaction.Pointer');
65548goog.require('ol.interaction.Property');
65549goog.require('ol.layer.Vector');
65550goog.require('ol.source.Vector');
65551goog.require('ol.style.Style');
65552
65553
65554/**
65555 * @classdesc
65556 * Interaction for drawing feature geometries.
65557 *
65558 * @constructor
65559 * @extends {ol.interaction.Pointer}
65560 * @fires ol.interaction.Draw.Event
65561 * @param {olx.interaction.DrawOptions} options Options.
65562 * @api
65563 */
65564ol.interaction.Draw = function(options) {
65565
65566 ol.interaction.Pointer.call(this, {
65567 handleDownEvent: ol.interaction.Draw.handleDownEvent_,
65568 handleEvent: ol.interaction.Draw.handleEvent,
65569 handleUpEvent: ol.interaction.Draw.handleUpEvent_
65570 });
65571
65572 /**
65573 * @type {boolean}
65574 * @private
65575 */
65576 this.shouldHandle_ = false;
65577
65578 /**
65579 * @type {ol.Pixel}
65580 * @private
65581 */
65582 this.downPx_ = null;
65583
65584 /**
65585 * @type {boolean}
65586 * @private
65587 */
65588 this.freehand_ = false;
65589
65590 /**
65591 * Target source for drawn features.
65592 * @type {ol.source.Vector}
65593 * @private
65594 */
65595 this.source_ = options.source ? options.source : null;
65596
65597 /**
65598 * Target collection for drawn features.
65599 * @type {ol.Collection.<ol.Feature>}
65600 * @private
65601 */
65602 this.features_ = options.features ? options.features : null;
65603
65604 /**
65605 * Pixel distance for snapping.
65606 * @type {number}
65607 * @private
65608 */
65609 this.snapTolerance_ = options.snapTolerance ? options.snapTolerance : 12;
65610
65611 /**
65612 * Geometry type.
65613 * @type {ol.geom.GeometryType}
65614 * @private
65615 */
65616 this.type_ = options.type;
65617
65618 /**
65619 * Drawing mode (derived from geometry type.
65620 * @type {ol.interaction.Draw.Mode_}
65621 * @private
65622 */
65623 this.mode_ = ol.interaction.Draw.getMode_(this.type_);
65624
65625 /**
65626 * The number of points that must be drawn before a polygon ring or line
65627 * string can be finished. The default is 3 for polygon rings and 2 for
65628 * line strings.
65629 * @type {number}
65630 * @private
65631 */
65632 this.minPoints_ = options.minPoints ?
65633 options.minPoints :
65634 (this.mode_ === ol.interaction.Draw.Mode_.POLYGON ? 3 : 2);
65635
65636 /**
65637 * The number of points that can be drawn before a polygon ring or line string
65638 * is finished. The default is no restriction.
65639 * @type {number}
65640 * @private
65641 */
65642 this.maxPoints_ = options.maxPoints ? options.maxPoints : Infinity;
65643
65644 /**
65645 * A function to decide if a potential finish coordinate is permissible
65646 * @private
65647 * @type {ol.EventsConditionType}
65648 */
65649 this.finishCondition_ = options.finishCondition ? options.finishCondition : ol.functions.TRUE;
65650
65651 var geometryFunction = options.geometryFunction;
65652 if (!geometryFunction) {
65653 if (this.type_ === ol.geom.GeometryType.CIRCLE) {
65654 /**
65655 * @param {!Array.<ol.Coordinate>} coordinates
65656 * The coordinates.
65657 * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
65658 * @return {ol.geom.SimpleGeometry} A geometry.
65659 */
65660 geometryFunction = function(coordinates, opt_geometry) {
65661 var circle = opt_geometry ? /** @type {ol.geom.Circle} */ (opt_geometry) :
65662 new ol.geom.Circle([NaN, NaN]);
65663 var squaredLength = ol.coordinate.squaredDistance(
65664 coordinates[0], coordinates[1]);
65665 circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength));
65666 return circle;
65667 };
65668 } else {
65669 var Constructor;
65670 var mode = this.mode_;
65671 if (mode === ol.interaction.Draw.Mode_.POINT) {
65672 Constructor = ol.geom.Point;
65673 } else if (mode === ol.interaction.Draw.Mode_.LINE_STRING) {
65674 Constructor = ol.geom.LineString;
65675 } else if (mode === ol.interaction.Draw.Mode_.POLYGON) {
65676 Constructor = ol.geom.Polygon;
65677 }
65678 /**
65679 * @param {!Array.<ol.Coordinate>} coordinates
65680 * The coordinates.
65681 * @param {ol.geom.SimpleGeometry=} opt_geometry Optional geometry.
65682 * @return {ol.geom.SimpleGeometry} A geometry.
65683 */
65684 geometryFunction = function(coordinates, opt_geometry) {
65685 var geometry = opt_geometry;
65686 if (geometry) {
65687 if (mode === ol.interaction.Draw.Mode_.POLYGON) {
65688 geometry.setCoordinates([coordinates[0].concat([coordinates[0][0]])]);
65689 } else {
65690 geometry.setCoordinates(coordinates);
65691 }
65692 } else {
65693 geometry = new Constructor(coordinates);
65694 }
65695 return geometry;
65696 };
65697 }
65698 }
65699
65700 /**
65701 * @type {ol.DrawGeometryFunctionType}
65702 * @private
65703 */
65704 this.geometryFunction_ = geometryFunction;
65705
65706 /**
65707 * Finish coordinate for the feature (first point for polygons, last point for
65708 * linestrings).
65709 * @type {ol.Coordinate}
65710 * @private
65711 */
65712 this.finishCoordinate_ = null;
65713
65714 /**
65715 * Sketch feature.
65716 * @type {ol.Feature}
65717 * @private
65718 */
65719 this.sketchFeature_ = null;
65720
65721 /**
65722 * Sketch point.
65723 * @type {ol.Feature}
65724 * @private
65725 */
65726 this.sketchPoint_ = null;
65727
65728 /**
65729 * Sketch coordinates. Used when drawing a line or polygon.
65730 * @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>}
65731 * @private
65732 */
65733 this.sketchCoords_ = null;
65734
65735 /**
65736 * Sketch line. Used when drawing polygon.
65737 * @type {ol.Feature}
65738 * @private
65739 */
65740 this.sketchLine_ = null;
65741
65742 /**
65743 * Sketch line coordinates. Used when drawing a polygon or circle.
65744 * @type {Array.<ol.Coordinate>}
65745 * @private
65746 */
65747 this.sketchLineCoords_ = null;
65748
65749 /**
65750 * Squared tolerance for handling up events. If the squared distance
65751 * between a down and up event is greater than this tolerance, up events
65752 * will not be handled.
65753 * @type {number}
65754 * @private
65755 */
65756 this.squaredClickTolerance_ = options.clickTolerance ?
65757 options.clickTolerance * options.clickTolerance : 36;
65758
65759 /**
65760 * Draw overlay where our sketch features are drawn.
65761 * @type {ol.layer.Vector}
65762 * @private
65763 */
65764 this.overlay_ = new ol.layer.Vector({
65765 source: new ol.source.Vector({
65766 useSpatialIndex: false,
65767 wrapX: options.wrapX ? options.wrapX : false
65768 }),
65769 style: options.style ? options.style :
65770 ol.interaction.Draw.getDefaultStyleFunction()
65771 });
65772
65773 /**
65774 * Name of the geometry attribute for newly created features.
65775 * @type {string|undefined}
65776 * @private
65777 */
65778 this.geometryName_ = options.geometryName;
65779
65780 /**
65781 * @private
65782 * @type {ol.EventsConditionType}
65783 */
65784 this.condition_ = options.condition ?
65785 options.condition : ol.events.condition.noModifierKeys;
65786
65787 /**
65788 * @private
65789 * @type {ol.EventsConditionType}
65790 */
65791 this.freehandCondition_;
65792 if (options.freehand) {
65793 this.freehandCondition_ = ol.events.condition.always;
65794 } else {
65795 this.freehandCondition_ = options.freehandCondition ?
65796 options.freehandCondition : ol.events.condition.shiftKeyOnly;
65797 }
65798
65799 ol.events.listen(this,
65800 ol.Object.getChangeEventType(ol.interaction.Property.ACTIVE),
65801 this.updateState_, this);
65802
65803};
65804ol.inherits(ol.interaction.Draw, ol.interaction.Pointer);
65805
65806
65807/**
65808 * @return {ol.StyleFunction} Styles.
65809 */
65810ol.interaction.Draw.getDefaultStyleFunction = function() {
65811 var styles = ol.style.Style.createDefaultEditing();
65812 return function(feature, resolution) {
65813 return styles[feature.getGeometry().getType()];
65814 };
65815};
65816
65817
65818/**
65819 * @inheritDoc
65820 */
65821ol.interaction.Draw.prototype.setMap = function(map) {
65822 ol.interaction.Pointer.prototype.setMap.call(this, map);
65823 this.updateState_();
65824};
65825
65826
65827/**
65828 * Handles the {@link ol.MapBrowserEvent map browser event} and may actually
65829 * draw or finish the drawing.
65830 * @param {ol.MapBrowserEvent} event Map browser event.
65831 * @return {boolean} `false` to stop event propagation.
65832 * @this {ol.interaction.Draw}
65833 * @api
65834 */
65835ol.interaction.Draw.handleEvent = function(event) {
65836 this.freehand_ = this.mode_ !== ol.interaction.Draw.Mode_.POINT && this.freehandCondition_(event);
65837 var pass = !this.freehand_;
65838 if (this.freehand_ &&
65839 event.type === ol.MapBrowserEventType.POINTERDRAG && this.sketchFeature_ !== null) {
65840 this.addToDrawing_(event);
65841 pass = false;
65842 } else if (event.type ===
65843 ol.MapBrowserEventType.POINTERMOVE) {
65844 pass = this.handlePointerMove_(event);
65845 } else if (event.type === ol.MapBrowserEventType.DBLCLICK) {
65846 pass = false;
65847 }
65848 return ol.interaction.Pointer.handleEvent.call(this, event) && pass;
65849};
65850
65851
65852/**
65853 * @param {ol.MapBrowserPointerEvent} event Event.
65854 * @return {boolean} Start drag sequence?
65855 * @this {ol.interaction.Draw}
65856 * @private
65857 */
65858ol.interaction.Draw.handleDownEvent_ = function(event) {
65859 this.shouldHandle_ = !this.freehand_;
65860
65861 if (this.freehand_) {
65862 this.downPx_ = event.pixel;
65863 if (!this.finishCoordinate_) {
65864 this.startDrawing_(event);
65865 }
65866 return true;
65867 } else if (this.condition_(event)) {
65868 this.downPx_ = event.pixel;
65869 return true;
65870 } else {
65871 return false;
65872 }
65873};
65874
65875
65876/**
65877 * @param {ol.MapBrowserPointerEvent} event Event.
65878 * @return {boolean} Stop drag sequence?
65879 * @this {ol.interaction.Draw}
65880 * @private
65881 */
65882ol.interaction.Draw.handleUpEvent_ = function(event) {
65883 var pass = true;
65884
65885 this.handlePointerMove_(event);
65886
65887 var circleMode = this.mode_ === ol.interaction.Draw.Mode_.CIRCLE;
65888
65889 if (this.shouldHandle_) {
65890 if (!this.finishCoordinate_) {
65891 this.startDrawing_(event);
65892 if (this.mode_ === ol.interaction.Draw.Mode_.POINT) {
65893 this.finishDrawing();
65894 }
65895 } else if (this.freehand_ || circleMode) {
65896 this.finishDrawing();
65897 } else if (this.atFinish_(event)) {
65898 if (this.finishCondition_(event)) {
65899 this.finishDrawing();
65900 }
65901 } else {
65902 this.addToDrawing_(event);
65903 }
65904 pass = false;
65905 } else if (this.freehand_) {
65906 this.finishCoordinate_ = null;
65907 this.abortDrawing_();
65908 }
65909 return pass;
65910};
65911
65912
65913/**
65914 * Handle move events.
65915 * @param {ol.MapBrowserEvent} event A move event.
65916 * @return {boolean} Pass the event to other interactions.
65917 * @private
65918 */
65919ol.interaction.Draw.prototype.handlePointerMove_ = function(event) {
65920 if (this.downPx_ &&
65921 ((!this.freehand_ && this.shouldHandle_) ||
65922 (this.freehand_ && !this.shouldHandle_))) {
65923 var downPx = this.downPx_;
65924 var clickPx = event.pixel;
65925 var dx = downPx[0] - clickPx[0];
65926 var dy = downPx[1] - clickPx[1];
65927 var squaredDistance = dx * dx + dy * dy;
65928 this.shouldHandle_ = this.freehand_ ?
65929 squaredDistance > this.squaredClickTolerance_ :
65930 squaredDistance <= this.squaredClickTolerance_;
65931 }
65932
65933 if (this.finishCoordinate_) {
65934 this.modifyDrawing_(event);
65935 } else {
65936 this.createOrUpdateSketchPoint_(event);
65937 }
65938 return true;
65939};
65940
65941
65942/**
65943 * Determine if an event is within the snapping tolerance of the start coord.
65944 * @param {ol.MapBrowserEvent} event Event.
65945 * @return {boolean} The event is within the snapping tolerance of the start.
65946 * @private
65947 */
65948ol.interaction.Draw.prototype.atFinish_ = function(event) {
65949 var at = false;
65950 if (this.sketchFeature_) {
65951 var potentiallyDone = false;
65952 var potentiallyFinishCoordinates = [this.finishCoordinate_];
65953 if (this.mode_ === ol.interaction.Draw.Mode_.LINE_STRING) {
65954 potentiallyDone = this.sketchCoords_.length > this.minPoints_;
65955 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
65956 potentiallyDone = this.sketchCoords_[0].length >
65957 this.minPoints_;
65958 potentiallyFinishCoordinates = [this.sketchCoords_[0][0],
65959 this.sketchCoords_[0][this.sketchCoords_[0].length - 2]];
65960 }
65961 if (potentiallyDone) {
65962 var map = event.map;
65963 for (var i = 0, ii = potentiallyFinishCoordinates.length; i < ii; i++) {
65964 var finishCoordinate = potentiallyFinishCoordinates[i];
65965 var finishPixel = map.getPixelFromCoordinate(finishCoordinate);
65966 var pixel = event.pixel;
65967 var dx = pixel[0] - finishPixel[0];
65968 var dy = pixel[1] - finishPixel[1];
65969 var snapTolerance = this.freehand_ ? 1 : this.snapTolerance_;
65970 at = Math.sqrt(dx * dx + dy * dy) <= snapTolerance;
65971 if (at) {
65972 this.finishCoordinate_ = finishCoordinate;
65973 break;
65974 }
65975 }
65976 }
65977 }
65978 return at;
65979};
65980
65981
65982/**
65983 * @param {ol.MapBrowserEvent} event Event.
65984 * @private
65985 */
65986ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) {
65987 var coordinates = event.coordinate.slice();
65988 if (!this.sketchPoint_) {
65989 this.sketchPoint_ = new ol.Feature(new ol.geom.Point(coordinates));
65990 this.updateSketchFeatures_();
65991 } else {
65992 var sketchPointGeom = /** @type {ol.geom.Point} */ (this.sketchPoint_.getGeometry());
65993 sketchPointGeom.setCoordinates(coordinates);
65994 }
65995};
65996
65997
65998/**
65999 * Start the drawing.
66000 * @param {ol.MapBrowserEvent} event Event.
66001 * @private
66002 */
66003ol.interaction.Draw.prototype.startDrawing_ = function(event) {
66004 var start = event.coordinate;
66005 this.finishCoordinate_ = start;
66006 if (this.mode_ === ol.interaction.Draw.Mode_.POINT) {
66007 this.sketchCoords_ = start.slice();
66008 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
66009 this.sketchCoords_ = [[start.slice(), start.slice()]];
66010 this.sketchLineCoords_ = this.sketchCoords_[0];
66011 } else {
66012 this.sketchCoords_ = [start.slice(), start.slice()];
66013 if (this.mode_ === ol.interaction.Draw.Mode_.CIRCLE) {
66014 this.sketchLineCoords_ = this.sketchCoords_;
66015 }
66016 }
66017 if (this.sketchLineCoords_) {
66018 this.sketchLine_ = new ol.Feature(
66019 new ol.geom.LineString(this.sketchLineCoords_));
66020 }
66021 var geometry = this.geometryFunction_(this.sketchCoords_);
66022 this.sketchFeature_ = new ol.Feature();
66023 if (this.geometryName_) {
66024 this.sketchFeature_.setGeometryName(this.geometryName_);
66025 }
66026 this.sketchFeature_.setGeometry(geometry);
66027 this.updateSketchFeatures_();
66028 this.dispatchEvent(new ol.interaction.Draw.Event(
66029 ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_));
66030};
66031
66032
66033/**
66034 * Modify the drawing.
66035 * @param {ol.MapBrowserEvent} event Event.
66036 * @private
66037 */
66038ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
66039 var coordinate = event.coordinate;
66040 var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());
66041 var coordinates, last;
66042 if (this.mode_ === ol.interaction.Draw.Mode_.POINT) {
66043 last = this.sketchCoords_;
66044 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
66045 coordinates = this.sketchCoords_[0];
66046 last = coordinates[coordinates.length - 1];
66047 if (this.atFinish_(event)) {
66048 // snap to finish
66049 coordinate = this.finishCoordinate_.slice();
66050 }
66051 } else {
66052 coordinates = this.sketchCoords_;
66053 last = coordinates[coordinates.length - 1];
66054 }
66055 last[0] = coordinate[0];
66056 last[1] = coordinate[1];
66057 this.geometryFunction_(/** @type {!Array.<ol.Coordinate>} */ (this.sketchCoords_), geometry);
66058 if (this.sketchPoint_) {
66059 var sketchPointGeom = /** @type {ol.geom.Point} */ (this.sketchPoint_.getGeometry());
66060 sketchPointGeom.setCoordinates(coordinate);
66061 }
66062 var sketchLineGeom;
66063 if (geometry instanceof ol.geom.Polygon &&
66064 this.mode_ !== ol.interaction.Draw.Mode_.POLYGON) {
66065 if (!this.sketchLine_) {
66066 this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null));
66067 }
66068 var ring = geometry.getLinearRing(0);
66069 sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());
66070 sketchLineGeom.setFlatCoordinates(
66071 ring.getLayout(), ring.getFlatCoordinates());
66072 } else if (this.sketchLineCoords_) {
66073 sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());
66074 sketchLineGeom.setCoordinates(this.sketchLineCoords_);
66075 }
66076 this.updateSketchFeatures_();
66077};
66078
66079
66080/**
66081 * Add a new coordinate to the drawing.
66082 * @param {ol.MapBrowserEvent} event Event.
66083 * @private
66084 */
66085ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
66086 var coordinate = event.coordinate;
66087 var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());
66088 var done;
66089 var coordinates;
66090 if (this.mode_ === ol.interaction.Draw.Mode_.LINE_STRING) {
66091 this.finishCoordinate_ = coordinate.slice();
66092 coordinates = this.sketchCoords_;
66093 if (coordinates.length >= this.maxPoints_) {
66094 if (this.freehand_) {
66095 coordinates.pop();
66096 } else {
66097 done = true;
66098 }
66099 }
66100 coordinates.push(coordinate.slice());
66101 this.geometryFunction_(coordinates, geometry);
66102 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
66103 coordinates = this.sketchCoords_[0];
66104 if (coordinates.length >= this.maxPoints_) {
66105 if (this.freehand_) {
66106 coordinates.pop();
66107 } else {
66108 done = true;
66109 }
66110 }
66111 coordinates.push(coordinate.slice());
66112 if (done) {
66113 this.finishCoordinate_ = coordinates[0];
66114 }
66115 this.geometryFunction_(this.sketchCoords_, geometry);
66116 }
66117 this.updateSketchFeatures_();
66118 if (done) {
66119 this.finishDrawing();
66120 }
66121};
66122
66123
66124/**
66125 * Remove last point of the feature currently being drawn.
66126 * @api
66127 */
66128ol.interaction.Draw.prototype.removeLastPoint = function() {
66129 if (!this.sketchFeature_) {
66130 return;
66131 }
66132 var geometry = /** @type {ol.geom.SimpleGeometry} */ (this.sketchFeature_.getGeometry());
66133 var coordinates, sketchLineGeom;
66134 if (this.mode_ === ol.interaction.Draw.Mode_.LINE_STRING) {
66135 coordinates = this.sketchCoords_;
66136 coordinates.splice(-2, 1);
66137 this.geometryFunction_(coordinates, geometry);
66138 if (coordinates.length >= 2) {
66139 this.finishCoordinate_ = coordinates[coordinates.length - 2].slice();
66140 }
66141 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
66142 coordinates = this.sketchCoords_[0];
66143 coordinates.splice(-2, 1);
66144 sketchLineGeom = /** @type {ol.geom.LineString} */ (this.sketchLine_.getGeometry());
66145 sketchLineGeom.setCoordinates(coordinates);
66146 this.geometryFunction_(this.sketchCoords_, geometry);
66147 }
66148
66149 if (coordinates.length === 0) {
66150 this.finishCoordinate_ = null;
66151 }
66152
66153 this.updateSketchFeatures_();
66154};
66155
66156
66157/**
66158 * Stop drawing and add the sketch feature to the target layer.
66159 * The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before
66160 * inserting the feature.
66161 * @api
66162 */
66163ol.interaction.Draw.prototype.finishDrawing = function() {
66164 var sketchFeature = this.abortDrawing_();
66165 var coordinates = this.sketchCoords_;
66166 var geometry = /** @type {ol.geom.SimpleGeometry} */ (sketchFeature.getGeometry());
66167 if (this.mode_ === ol.interaction.Draw.Mode_.LINE_STRING) {
66168 // remove the redundant last point
66169 coordinates.pop();
66170 this.geometryFunction_(coordinates, geometry);
66171 } else if (this.mode_ === ol.interaction.Draw.Mode_.POLYGON) {
66172 // remove the redundant last point in ring
66173 coordinates[0].pop();
66174 this.geometryFunction_(coordinates, geometry);
66175 coordinates = geometry.getCoordinates();
66176 }
66177
66178 // cast multi-part geometries
66179 if (this.type_ === ol.geom.GeometryType.MULTI_POINT) {
66180 sketchFeature.setGeometry(new ol.geom.MultiPoint([coordinates]));
66181 } else if (this.type_ === ol.geom.GeometryType.MULTI_LINE_STRING) {
66182 sketchFeature.setGeometry(new ol.geom.MultiLineString([coordinates]));
66183 } else if (this.type_ === ol.geom.GeometryType.MULTI_POLYGON) {
66184 sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));
66185 }
66186
66187 // First dispatch event to allow full set up of feature
66188 this.dispatchEvent(new ol.interaction.Draw.Event(
66189 ol.interaction.DrawEventType.DRAWEND, sketchFeature));
66190
66191 // Then insert feature
66192 if (this.features_) {
66193 this.features_.push(sketchFeature);
66194 }
66195 if (this.source_) {
66196 this.source_.addFeature(sketchFeature);
66197 }
66198};
66199
66200
66201/**
66202 * Stop drawing without adding the sketch feature to the target layer.
66203 * @return {ol.Feature} The sketch feature (or null if none).
66204 * @private
66205 */
66206ol.interaction.Draw.prototype.abortDrawing_ = function() {
66207 this.finishCoordinate_ = null;
66208 var sketchFeature = this.sketchFeature_;
66209 if (sketchFeature) {
66210 this.sketchFeature_ = null;
66211 this.sketchPoint_ = null;
66212 this.sketchLine_ = null;
66213 this.overlay_.getSource().clear(true);
66214 }
66215 return sketchFeature;
66216};
66217
66218
66219/**
66220 * Extend an existing geometry by adding additional points. This only works
66221 * on features with `LineString` geometries, where the interaction will
66222 * extend lines by adding points to the end of the coordinates array.
66223 * @param {!ol.Feature} feature Feature to be extended.
66224 * @api
66225 */
66226ol.interaction.Draw.prototype.extend = function(feature) {
66227 var geometry = feature.getGeometry();
66228 var lineString = /** @type {ol.geom.LineString} */ (geometry);
66229 this.sketchFeature_ = feature;
66230 this.sketchCoords_ = lineString.getCoordinates();
66231 var last = this.sketchCoords_[this.sketchCoords_.length - 1];
66232 this.finishCoordinate_ = last.slice();
66233 this.sketchCoords_.push(last.slice());
66234 this.updateSketchFeatures_();
66235 this.dispatchEvent(new ol.interaction.Draw.Event(
66236 ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_));
66237};
66238
66239
66240/**
66241 * @inheritDoc
66242 */
66243ol.interaction.Draw.prototype.shouldStopEvent = ol.functions.FALSE;
66244
66245
66246/**
66247 * Redraw the sketch features.
66248 * @private
66249 */
66250ol.interaction.Draw.prototype.updateSketchFeatures_ = function() {
66251 var sketchFeatures = [];
66252 if (this.sketchFeature_) {
66253 sketchFeatures.push(this.sketchFeature_);
66254 }
66255 if (this.sketchLine_) {
66256 sketchFeatures.push(this.sketchLine_);
66257 }
66258 if (this.sketchPoint_) {
66259 sketchFeatures.push(this.sketchPoint_);
66260 }
66261 var overlaySource = this.overlay_.getSource();
66262 overlaySource.clear(true);
66263 overlaySource.addFeatures(sketchFeatures);
66264};
66265
66266
66267/**
66268 * @private
66269 */
66270ol.interaction.Draw.prototype.updateState_ = function() {
66271 var map = this.getMap();
66272 var active = this.getActive();
66273 if (!map || !active) {
66274 this.abortDrawing_();
66275 }
66276 this.overlay_.setMap(active ? map : null);
66277};
66278
66279
66280/**
66281 * Create a `geometryFunction` for `type: 'Circle'` that will create a regular
66282 * polygon with a user specified number of sides and start angle instead of an
66283 * `ol.geom.Circle` geometry.
66284 * @param {number=} opt_sides Number of sides of the regular polygon. Default is
66285 * 32.
66286 * @param {number=} opt_angle Angle of the first point in radians. 0 means East.
66287 * Default is the angle defined by the heading from the center of the
66288 * regular polygon to the current pointer position.
66289 * @return {ol.DrawGeometryFunctionType} Function that draws a
66290 * polygon.
66291 * @api
66292 */
66293ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) {
66294 return (
66295 /**
66296 * @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
66297 * @param {ol.geom.SimpleGeometry=} opt_geometry
66298 * @return {ol.geom.SimpleGeometry}
66299 */
66300 function(coordinates, opt_geometry) {
66301 var center = coordinates[0];
66302 var end = coordinates[1];
66303 var radius = Math.sqrt(
66304 ol.coordinate.squaredDistance(center, end));
66305 var geometry = opt_geometry ? /** @type {ol.geom.Polygon} */ (opt_geometry) :
66306 ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides);
66307 var angle = opt_angle ? opt_angle :
66308 Math.atan((end[1] - center[1]) / (end[0] - center[0]));
66309 ol.geom.Polygon.makeRegular(geometry, center, radius, angle);
66310 return geometry;
66311 }
66312 );
66313};
66314
66315
66316/**
66317 * Create a `geometryFunction` that will create a box-shaped polygon (aligned
66318 * with the coordinate system axes). Use this with the draw interaction and
66319 * `type: 'Circle'` to return a box instead of a circle geometry.
66320 * @return {ol.DrawGeometryFunctionType} Function that draws a box-shaped polygon.
66321 * @api
66322 */
66323ol.interaction.Draw.createBox = function() {
66324 return (
66325 /**
66326 * @param {Array.<ol.Coordinate>} coordinates
66327 * @param {ol.geom.SimpleGeometry=} opt_geometry
66328 * @return {ol.geom.SimpleGeometry}
66329 */
66330 function(coordinates, opt_geometry) {
66331 var extent = ol.extent.boundingExtent(coordinates);
66332 var geometry = opt_geometry || new ol.geom.Polygon(null);
66333 geometry.setCoordinates([[
66334 ol.extent.getBottomLeft(extent),
66335 ol.extent.getBottomRight(extent),
66336 ol.extent.getTopRight(extent),
66337 ol.extent.getTopLeft(extent),
66338 ol.extent.getBottomLeft(extent)
66339 ]]);
66340 return geometry;
66341 }
66342 );
66343};
66344
66345
66346/**
66347 * Get the drawing mode. The mode for mult-part geometries is the same as for
66348 * their single-part cousins.
66349 * @param {ol.geom.GeometryType} type Geometry type.
66350 * @return {ol.interaction.Draw.Mode_} Drawing mode.
66351 * @private
66352 */
66353ol.interaction.Draw.getMode_ = function(type) {
66354 var mode;
66355 if (type === ol.geom.GeometryType.POINT ||
66356 type === ol.geom.GeometryType.MULTI_POINT) {
66357 mode = ol.interaction.Draw.Mode_.POINT;
66358 } else if (type === ol.geom.GeometryType.LINE_STRING ||
66359 type === ol.geom.GeometryType.MULTI_LINE_STRING) {
66360 mode = ol.interaction.Draw.Mode_.LINE_STRING;
66361 } else if (type === ol.geom.GeometryType.POLYGON ||
66362 type === ol.geom.GeometryType.MULTI_POLYGON) {
66363 mode = ol.interaction.Draw.Mode_.POLYGON;
66364 } else if (type === ol.geom.GeometryType.CIRCLE) {
66365 mode = ol.interaction.Draw.Mode_.CIRCLE;
66366 }
66367 return /** @type {!ol.interaction.Draw.Mode_} */ (mode);
66368};
66369
66370
66371/**
66372 * Draw mode. This collapses multi-part geometry types with their single-part
66373 * cousins.
66374 * @enum {string}
66375 * @private
66376 */
66377ol.interaction.Draw.Mode_ = {
66378 POINT: 'Point',
66379 LINE_STRING: 'LineString',
66380 POLYGON: 'Polygon',
66381 CIRCLE: 'Circle'
66382};
66383
66384/**
66385 * @classdesc
66386 * Events emitted by {@link ol.interaction.Draw} instances are instances of
66387 * this type.
66388 *
66389 * @constructor
66390 * @extends {ol.events.Event}
66391 * @implements {oli.DrawEvent}
66392 * @param {ol.interaction.DrawEventType} type Type.
66393 * @param {ol.Feature} feature The feature drawn.
66394 */
66395ol.interaction.Draw.Event = function(type, feature) {
66396
66397 ol.events.Event.call(this, type);
66398
66399 /**
66400 * The feature being drawn.
66401 * @type {ol.Feature}
66402 * @api
66403 */
66404 this.feature = feature;
66405
66406};
66407ol.inherits(ol.interaction.Draw.Event, ol.events.Event);
66408
66409goog.provide('ol.interaction.ExtentEventType');
66410
66411
66412/**
66413 * @enum {string}
66414 */
66415ol.interaction.ExtentEventType = {
66416 /**
66417 * Triggered after the extent is changed
66418 * @event ol.interaction.Extent.Event#extentchanged
66419 * @api
66420 */
66421 EXTENTCHANGED: 'extentchanged'
66422};
66423
66424goog.provide('ol.interaction.Extent');
66425
66426goog.require('ol');
66427goog.require('ol.Feature');
66428goog.require('ol.MapBrowserEventType');
66429goog.require('ol.MapBrowserPointerEvent');
66430goog.require('ol.coordinate');
66431goog.require('ol.events.Event');
66432goog.require('ol.extent');
66433goog.require('ol.geom.GeometryType');
66434goog.require('ol.geom.Point');
66435goog.require('ol.geom.Polygon');
66436goog.require('ol.interaction.ExtentEventType');
66437goog.require('ol.interaction.Pointer');
66438goog.require('ol.layer.Vector');
66439goog.require('ol.source.Vector');
66440goog.require('ol.style.Style');
66441
66442
66443/**
66444 * @classdesc
66445 * Allows the user to draw a vector box by clicking and dragging on the map.
66446 * Once drawn, the vector box can be modified by dragging its vertices or edges.
66447 * This interaction is only supported for mouse devices.
66448 *
66449 * @constructor
66450 * @extends {ol.interaction.Pointer}
66451 * @fires ol.interaction.Extent.Event
66452 * @param {olx.interaction.ExtentOptions=} opt_options Options.
66453 * @api
66454 */
66455ol.interaction.Extent = function(opt_options) {
66456
66457 /**
66458 * Extent of the drawn box
66459 * @type {ol.Extent}
66460 * @private
66461 */
66462 this.extent_ = null;
66463
66464 /**
66465 * Handler for pointer move events
66466 * @type {function (ol.Coordinate): ol.Extent|null}
66467 * @private
66468 */
66469 this.pointerHandler_ = null;
66470
66471 /**
66472 * Pixel threshold to snap to extent
66473 * @type {number}
66474 * @private
66475 */
66476 this.pixelTolerance_ = 10;
66477
66478 /**
66479 * Is the pointer snapped to an extent vertex
66480 * @type {boolean}
66481 * @private
66482 */
66483 this.snappedToVertex_ = false;
66484
66485 /**
66486 * Feature for displaying the visible extent
66487 * @type {ol.Feature}
66488 * @private
66489 */
66490 this.extentFeature_ = null;
66491
66492 /**
66493 * Feature for displaying the visible pointer
66494 * @type {ol.Feature}
66495 * @private
66496 */
66497 this.vertexFeature_ = null;
66498
66499 if (!opt_options) {
66500 opt_options = {};
66501 }
66502
66503 /* Inherit ol.interaction.Pointer */
66504 ol.interaction.Pointer.call(this, {
66505 handleDownEvent: ol.interaction.Extent.handleDownEvent_,
66506 handleDragEvent: ol.interaction.Extent.handleDragEvent_,
66507 handleEvent: ol.interaction.Extent.handleEvent_,
66508 handleUpEvent: ol.interaction.Extent.handleUpEvent_
66509 });
66510
66511 /**
66512 * Layer for the extentFeature
66513 * @type {ol.layer.Vector}
66514 * @private
66515 */
66516 this.extentOverlay_ = new ol.layer.Vector({
66517 source: new ol.source.Vector({
66518 useSpatialIndex: false,
66519 wrapX: !!opt_options.wrapX
66520 }),
66521 style: opt_options.boxStyle ? opt_options.boxStyle : ol.interaction.Extent.getDefaultExtentStyleFunction_(),
66522 updateWhileAnimating: true,
66523 updateWhileInteracting: true
66524 });
66525
66526 /**
66527 * Layer for the vertexFeature
66528 * @type {ol.layer.Vector}
66529 * @private
66530 */
66531 this.vertexOverlay_ = new ol.layer.Vector({
66532 source: new ol.source.Vector({
66533 useSpatialIndex: false,
66534 wrapX: !!opt_options.wrapX
66535 }),
66536 style: opt_options.pointerStyle ? opt_options.pointerStyle : ol.interaction.Extent.getDefaultPointerStyleFunction_(),
66537 updateWhileAnimating: true,
66538 updateWhileInteracting: true
66539 });
66540
66541 if (opt_options.extent) {
66542 this.setExtent(opt_options.extent);
66543 }
66544};
66545
66546ol.inherits(ol.interaction.Extent, ol.interaction.Pointer);
66547
66548/**
66549 * @param {ol.MapBrowserEvent} mapBrowserEvent Event.
66550 * @return {boolean} Propagate event?
66551 * @this {ol.interaction.Extent}
66552 * @private
66553 */
66554ol.interaction.Extent.handleEvent_ = function(mapBrowserEvent) {
66555 if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
66556 return true;
66557 }
66558 //display pointer (if not dragging)
66559 if (mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE && !this.handlingDownUpSequence) {
66560 this.handlePointerMove_(mapBrowserEvent);
66561 }
66562 //call pointer to determine up/down/drag
66563 ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent);
66564 //return false to stop propagation
66565 return false;
66566};
66567
66568/**
66569 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
66570 * @return {boolean} Event handled?
66571 * @this {ol.interaction.Extent}
66572 * @private
66573 */
66574ol.interaction.Extent.handleDownEvent_ = function(mapBrowserEvent) {
66575 var pixel = mapBrowserEvent.pixel;
66576 var map = mapBrowserEvent.map;
66577
66578 var extent = this.getExtent();
66579 var vertex = this.snapToVertex_(pixel, map);
66580
66581 //find the extent corner opposite the passed corner
66582 var getOpposingPoint = function(point) {
66583 var x_ = null;
66584 var y_ = null;
66585 if (point[0] == extent[0]) {
66586 x_ = extent[2];
66587 } else if (point[0] == extent[2]) {
66588 x_ = extent[0];
66589 }
66590 if (point[1] == extent[1]) {
66591 y_ = extent[3];
66592 } else if (point[1] == extent[3]) {
66593 y_ = extent[1];
66594 }
66595 if (x_ !== null && y_ !== null) {
66596 return [x_, y_];
66597 }
66598 return null;
66599 };
66600 if (vertex && extent) {
66601 var x = (vertex[0] == extent[0] || vertex[0] == extent[2]) ? vertex[0] : null;
66602 var y = (vertex[1] == extent[1] || vertex[1] == extent[3]) ? vertex[1] : null;
66603
66604 //snap to point
66605 if (x !== null && y !== null) {
66606 this.pointerHandler_ = ol.interaction.Extent.getPointHandler_(getOpposingPoint(vertex));
66607 //snap to edge
66608 } else if (x !== null) {
66609 this.pointerHandler_ = ol.interaction.Extent.getEdgeHandler_(
66610 getOpposingPoint([x, extent[1]]),
66611 getOpposingPoint([x, extent[3]])
66612 );
66613 } else if (y !== null) {
66614 this.pointerHandler_ = ol.interaction.Extent.getEdgeHandler_(
66615 getOpposingPoint([extent[0], y]),
66616 getOpposingPoint([extent[2], y])
66617 );
66618 }
66619 //no snap - new bbox
66620 } else {
66621 vertex = map.getCoordinateFromPixel(pixel);
66622 this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]);
66623 this.pointerHandler_ = ol.interaction.Extent.getPointHandler_(vertex);
66624 }
66625 return true; //event handled; start downup sequence
66626};
66627
66628/**
66629 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
66630 * @return {boolean} Event handled?
66631 * @this {ol.interaction.Extent}
66632 * @private
66633 */
66634ol.interaction.Extent.handleDragEvent_ = function(mapBrowserEvent) {
66635 if (this.pointerHandler_) {
66636 var pixelCoordinate = mapBrowserEvent.coordinate;
66637 this.setExtent(this.pointerHandler_(pixelCoordinate));
66638 this.createOrUpdatePointerFeature_(pixelCoordinate);
66639 }
66640 return true;
66641};
66642
66643/**
66644 * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event.
66645 * @return {boolean} Stop drag sequence?
66646 * @this {ol.interaction.Extent}
66647 * @private
66648 */
66649ol.interaction.Extent.handleUpEvent_ = function(mapBrowserEvent) {
66650 this.pointerHandler_ = null;
66651 //If bbox is zero area, set to null;
66652 var extent = this.getExtent();
66653 if (!extent || ol.extent.getArea(extent) === 0) {
66654 this.setExtent(null);
66655 }
66656 return false; //Stop handling downup sequence
66657};
66658
66659/**
66660 * Returns the default style for the drawn bbox
66661 *
66662 * @return {ol.StyleFunction} Default Extent style
66663 * @private
66664 */
66665ol.interaction.Extent.getDefaultExtentStyleFunction_ = function() {
66666 var style = ol.style.Style.createDefaultEditing();
66667 return function(feature, resolution) {
66668 return style[ol.geom.GeometryType.POLYGON];
66669 };
66670};
66671
66672/**
66673 * Returns the default style for the pointer
66674 *
66675 * @return {ol.StyleFunction} Default pointer style
66676 * @private
66677 */
66678ol.interaction.Extent.getDefaultPointerStyleFunction_ = function() {
66679 var style = ol.style.Style.createDefaultEditing();
66680 return function(feature, resolution) {
66681 return style[ol.geom.GeometryType.POINT];
66682 };
66683};
66684
66685/**
66686 * @param {ol.Coordinate} fixedPoint corner that will be unchanged in the new extent
66687 * @returns {function (ol.Coordinate): ol.Extent} event handler
66688 * @private
66689 */
66690ol.interaction.Extent.getPointHandler_ = function(fixedPoint) {
66691 return function(point) {
66692 return ol.extent.boundingExtent([fixedPoint, point]);
66693 };
66694};
66695
66696/**
66697 * @param {ol.Coordinate} fixedP1 first corner that will be unchanged in the new extent
66698 * @param {ol.Coordinate} fixedP2 second corner that will be unchanged in the new extent
66699 * @returns {function (ol.Coordinate): ol.Extent|null} event handler
66700 * @private
66701 */
66702ol.interaction.Extent.getEdgeHandler_ = function(fixedP1, fixedP2) {
66703 if (fixedP1[0] == fixedP2[0]) {
66704 return function(point) {
66705 return ol.extent.boundingExtent([fixedP1, [point[0], fixedP2[1]]]);
66706 };
66707 } else if (fixedP1[1] == fixedP2[1]) {
66708 return function(point) {
66709 return ol.extent.boundingExtent([fixedP1, [fixedP2[0], point[1]]]);
66710 };
66711 } else {
66712 return null;
66713 }
66714};
66715
66716/**
66717 * @param {ol.Extent} extent extent
66718 * @returns {Array<Array<ol.Coordinate>>} extent line segments
66719 * @private
66720 */
66721ol.interaction.Extent.getSegments_ = function(extent) {
66722 return [
66723 [[extent[0], extent[1]], [extent[0], extent[3]]],
66724 [[extent[0], extent[3]], [extent[2], extent[3]]],
66725 [[extent[2], extent[3]], [extent[2], extent[1]]],
66726 [[extent[2], extent[1]], [extent[0], extent[1]]]
66727 ];
66728};
66729
66730/**
66731 * @param {ol.Pixel} pixel cursor location
66732 * @param {ol.Map} map map
66733 * @returns {ol.Coordinate|null} snapped vertex on extent
66734 * @private
66735 */
66736ol.interaction.Extent.prototype.snapToVertex_ = function(pixel, map) {
66737 var pixelCoordinate = map.getCoordinateFromPixel(pixel);
66738 var sortByDistance = function(a, b) {
66739 return ol.coordinate.squaredDistanceToSegment(pixelCoordinate, a) -
66740 ol.coordinate.squaredDistanceToSegment(pixelCoordinate, b);
66741 };
66742 var extent = this.getExtent();
66743 if (extent) {
66744 //convert extents to line segments and find the segment closest to pixelCoordinate
66745 var segments = ol.interaction.Extent.getSegments_(extent);
66746 segments.sort(sortByDistance);
66747 var closestSegment = segments[0];
66748
66749 var vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,
66750 closestSegment));
66751 var vertexPixel = map.getPixelFromCoordinate(vertex);
66752
66753 //if the distance is within tolerance, snap to the segment
66754 if (ol.coordinate.distance(pixel, vertexPixel) <= this.pixelTolerance_) {
66755 //test if we should further snap to a vertex
66756 var pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
66757 var pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
66758 var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
66759 var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
66760 var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
66761 this.snappedToVertex_ = dist <= this.pixelTolerance_;
66762 if (this.snappedToVertex_) {
66763 vertex = squaredDist1 > squaredDist2 ?
66764 closestSegment[1] : closestSegment[0];
66765 }
66766 return vertex;
66767 }
66768 }
66769 return null;
66770};
66771
66772/**
66773 * @param {ol.MapBrowserEvent} mapBrowserEvent pointer move event
66774 * @private
66775 */
66776ol.interaction.Extent.prototype.handlePointerMove_ = function(mapBrowserEvent) {
66777 var pixel = mapBrowserEvent.pixel;
66778 var map = mapBrowserEvent.map;
66779
66780 var vertex = this.snapToVertex_(pixel, map);
66781 if (!vertex) {
66782 vertex = map.getCoordinateFromPixel(pixel);
66783 }
66784 this.createOrUpdatePointerFeature_(vertex);
66785};
66786
66787/**
66788 * @param {ol.Extent} extent extent
66789 * @returns {ol.Feature} extent as featrue
66790 * @private
66791 */
66792ol.interaction.Extent.prototype.createOrUpdateExtentFeature_ = function(extent) {
66793 var extentFeature = this.extentFeature_;
66794
66795 if (!extentFeature) {
66796 if (!extent) {
66797 extentFeature = new ol.Feature({});
66798 } else {
66799 extentFeature = new ol.Feature(ol.geom.Polygon.fromExtent(extent));
66800 }
66801 this.extentFeature_ = extentFeature;
66802 this.extentOverlay_.getSource().addFeature(extentFeature);
66803 } else {
66804 if (!extent) {
66805 extentFeature.setGeometry(undefined);
66806 } else {
66807 extentFeature.setGeometry(ol.geom.Polygon.fromExtent(extent));
66808 }
66809 }
66810 return extentFeature;
66811};
66812
66813
66814/**
66815 * @param {ol.Coordinate} vertex location of feature
66816 * @returns {ol.Feature} vertex as feature
66817 * @private
66818 */
66819ol.interaction.Extent.prototype.createOrUpdatePointerFeature_ = function(vertex) {
66820 var vertexFeature = this.vertexFeature_;
66821 if (!vertexFeature) {
66822 vertexFeature = new ol.Feature(new ol.geom.Point(vertex));
66823 this.vertexFeature_ = vertexFeature;
66824 this.vertexOverlay_.getSource().addFeature(vertexFeature);
66825 } else {
66826 var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
66827 geometry.setCoordinates(vertex);
66828 }
66829 return vertexFeature;
66830};
66831
66832
66833/**
66834 * @inheritDoc
66835 */
66836ol.interaction.Extent.prototype.setMap = function(map) {
66837 this.extentOverlay_.setMap(map);
66838 this.vertexOverlay_.setMap(map);
66839 ol.interaction.Pointer.prototype.setMap.call(this, map);
66840};
66841
66842/**
66843 * Returns the current drawn extent in the view projection
66844 *
66845 * @return {ol.Extent} Drawn extent in the view projection.
66846 * @api
66847 */
66848ol.interaction.Extent.prototype.getExtent = function() {
66849 return this.extent_;
66850};
66851
66852/**
66853 * Manually sets the drawn extent, using the view projection.
66854 *
66855 * @param {ol.Extent} extent Extent
66856 * @api
66857 */
66858ol.interaction.Extent.prototype.setExtent = function(extent) {
66859 //Null extent means no bbox
66860 this.extent_ = extent ? extent : null;
66861 this.createOrUpdateExtentFeature_(extent);
66862 this.dispatchEvent(new ol.interaction.Extent.Event(this.extent_));
66863};
66864
66865
66866/**
66867 * @classdesc
66868 * Events emitted by {@link ol.interaction.Extent} instances are instances of
66869 * this type.
66870 *
66871 * @constructor
66872 * @implements {oli.ExtentEvent}
66873 * @param {ol.Extent} extent the new extent
66874 * @extends {ol.events.Event}
66875 */
66876ol.interaction.Extent.Event = function(extent) {
66877 ol.events.Event.call(this, ol.interaction.ExtentEventType.EXTENTCHANGED);
66878
66879 /**
66880 * The current extent.
66881 * @type {ol.Extent}
66882 * @api
66883 */
66884 this.extent = extent;
66885
66886};
66887ol.inherits(ol.interaction.Extent.Event, ol.events.Event);
66888
66889goog.provide('ol.interaction.ModifyEventType');
66890
66891
66892/**
66893 * @enum {string}
66894 */
66895ol.interaction.ModifyEventType = {
66896 /**
66897 * Triggered upon feature modification start
66898 * @event ol.interaction.Modify.Event#modifystart
66899 * @api
66900 */
66901 MODIFYSTART: 'modifystart',
66902 /**
66903 * Triggered upon feature modification end
66904 * @event ol.interaction.Modify.Event#modifyend
66905 * @api
66906 */
66907 MODIFYEND: 'modifyend'
66908};
66909
66910goog.provide('ol.interaction.Modify');
66911
66912goog.require('ol');
66913goog.require('ol.Collection');
66914goog.require('ol.CollectionEventType');
66915goog.require('ol.Feature');
66916goog.require('ol.MapBrowserEventType');
66917goog.require('ol.MapBrowserPointerEvent');
66918goog.require('ol.ViewHint');
66919goog.require('ol.array');
66920goog.require('ol.coordinate');
66921goog.require('ol.events');
66922goog.require('ol.events.Event');
66923goog.require('ol.events.EventType');
66924goog.require('ol.events.condition');
66925goog.require('ol.extent');
66926goog.require('ol.geom.GeometryType');
66927goog.require('ol.geom.Point');
66928goog.require('ol.interaction.ModifyEventType');
66929goog.require('ol.interaction.Pointer');
66930goog.require('ol.layer.Vector');
66931goog.require('ol.source.Vector');
66932goog.require('ol.source.VectorEventType');
66933goog.require('ol.structs.RBush');
66934goog.require('ol.style.Style');
66935
66936/**
66937 * @classdesc
66938 * Interaction for modifying feature geometries. To modify features that have
66939 * been added to an existing source, construct the modify interaction with the
66940 * `source` option. If you want to modify features in a collection (for example,
66941 * the collection used by a select interaction), construct the interaction with
66942 * the `features` option. The interaction must be constructed with either a
66943 * `source` or `features` option.
66944 *
66945 * By default, the interaction will allow deletion of vertices when the `alt`
66946 * key is pressed. To configure the interaction with a different condition
66947 * for deletion, use the `deleteCondition` option.
66948 *
66949 * @constructor
66950 * @extends {ol.interaction.Pointer}
66951 * @param {olx.interaction.ModifyOptions} options Options.
66952 * @fires ol.interaction.Modify.Event
66953 * @api
66954 */
66955ol.interaction.Modify = function(options) {
66956
66957 ol.interaction.Pointer.call(this, {
66958 handleDownEvent: ol.interaction.Modify.handleDownEvent_,
66959 handleDragEvent: ol.interaction.Modify.handleDragEvent_,
66960 handleEvent: ol.interaction.Modify.handleEvent,
66961 handleUpEvent: ol.interaction.Modify.handleUpEvent_
66962 });
66963
66964 /**
66965 * @private
66966 * @type {ol.EventsConditionType}
66967 */
66968 this.condition_ = options.condition ?
66969 options.condition : ol.events.condition.primaryAction;
66970
66971
66972 /**
66973 * @private
66974 * @param {ol.MapBrowserEvent} mapBrowserEvent Browser event.
66975 * @return {boolean} Combined condition result.
66976 */
66977 this.defaultDeleteCondition_ = function(mapBrowserEvent) {
66978 return ol.events.condition.altKeyOnly(mapBrowserEvent) &&
66979 ol.events.condition.singleClick(mapBrowserEvent);
66980 };
66981
66982 /**
66983 * @type {ol.EventsConditionType}
66984 * @private
66985 */
66986 this.deleteCondition_ = options.deleteCondition ?
66987 options.deleteCondition : this.defaultDeleteCondition_;
66988
66989 /**
66990 * @type {ol.EventsConditionType}
66991 * @private
66992 */
66993 this.insertVertexCondition_ = options.insertVertexCondition ?
66994 options.insertVertexCondition : ol.events.condition.always;
66995
66996 /**
66997 * Editing vertex.
66998 * @type {ol.Feature}
66999 * @private
67000 */
67001 this.vertexFeature_ = null;
67002
67003 /**
67004 * Segments intersecting {@link this.vertexFeature_} by segment uid.
67005 * @type {Object.<string, boolean>}
67006 * @private
67007 */
67008 this.vertexSegments_ = null;
67009
67010 /**
67011 * @type {ol.Pixel}
67012 * @private
67013 */
67014 this.lastPixel_ = [0, 0];
67015
67016 /**
67017 * Tracks if the next `singleclick` event should be ignored to prevent
67018 * accidental deletion right after vertex creation.
67019 * @type {boolean}
67020 * @private
67021 */
67022 this.ignoreNextSingleClick_ = false;
67023
67024 /**
67025 * @type {boolean}
67026 * @private
67027 */
67028 this.modified_ = false;
67029
67030 /**
67031 * Segment RTree for each layer
67032 * @type {ol.structs.RBush.<ol.ModifySegmentDataType>}
67033 * @private
67034 */
67035 this.rBush_ = new ol.structs.RBush();
67036
67037 /**
67038 * @type {number}
67039 * @private
67040 */
67041 this.pixelTolerance_ = options.pixelTolerance !== undefined ?
67042 options.pixelTolerance : 10;
67043
67044 /**
67045 * @type {boolean}
67046 * @private
67047 */
67048 this.snappedToVertex_ = false;
67049
67050 /**
67051 * Indicate whether the interaction is currently changing a feature's
67052 * coordinates.
67053 * @type {boolean}
67054 * @private
67055 */
67056 this.changingFeature_ = false;
67057
67058 /**
67059 * @type {Array}
67060 * @private
67061 */
67062 this.dragSegments_ = [];
67063
67064 /**
67065 * Draw overlay where sketch features are drawn.
67066 * @type {ol.layer.Vector}
67067 * @private
67068 */
67069 this.overlay_ = new ol.layer.Vector({
67070 source: new ol.source.Vector({
67071 useSpatialIndex: false,
67072 wrapX: !!options.wrapX
67073 }),
67074 style: options.style ? options.style :
67075 ol.interaction.Modify.getDefaultStyleFunction(),
67076 updateWhileAnimating: true,
67077 updateWhileInteracting: true
67078 });
67079
67080 /**
67081 * @const
67082 * @private
67083 * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}
67084 */
67085 this.SEGMENT_WRITERS_ = {
67086 'Point': this.writePointGeometry_,
67087 'LineString': this.writeLineStringGeometry_,
67088 'LinearRing': this.writeLineStringGeometry_,
67089 'Polygon': this.writePolygonGeometry_,
67090 'MultiPoint': this.writeMultiPointGeometry_,
67091 'MultiLineString': this.writeMultiLineStringGeometry_,
67092 'MultiPolygon': this.writeMultiPolygonGeometry_,
67093 'Circle': this.writeCircleGeometry_,
67094 'GeometryCollection': this.writeGeometryCollectionGeometry_
67095 };
67096
67097
67098 /**
67099 * @type {ol.source.Vector}
67100 * @private
67101 */
67102 this.source_ = null;
67103
67104 var features;
67105 if (options.source) {
67106 this.source_ = options.source;
67107 features = new ol.Collection(this.source_.getFeatures());
67108 ol.events.listen(this.source_, ol.source.VectorEventType.ADDFEATURE,
67109 this.handleSourceAdd_, this);
67110 ol.events.listen(this.source_, ol.source.VectorEventType.REMOVEFEATURE,
67111 this.handleSourceRemove_, this);
67112 } else {
67113 features = options.features;
67114 }
67115 if (!features) {
67116 throw new Error('The modify interaction requires features or a source');
67117 }
67118
67119 /**
67120 * @type {ol.Collection.<ol.Feature>}
67121 * @private
67122 */
67123 this.features_ = features;
67124
67125 this.features_.forEach(this.addFeature_, this);
67126 ol.events.listen(this.features_, ol.CollectionEventType.ADD,
67127 this.handleFeatureAdd_, this);
67128 ol.events.listen(this.features_, ol.CollectionEventType.REMOVE,
67129 this.handleFeatureRemove_, this);
67130
67131 /**
67132 * @type {ol.MapBrowserPointerEvent}
67133 * @private
67134 */
67135 this.lastPointerEvent_ = null;
67136
67137};
67138ol.inherits(ol.interaction.Modify, ol.interaction.Pointer);
67139
67140
67141/**
67142 * @define {number} The segment index assigned to a circle's center when
67143 * breaking up a cicrle into ModifySegmentDataType segments.
67144 */
67145ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CENTER_INDEX = 0;
67146
67147/**
67148 * @define {number} The segment index assigned to a circle's circumference when
67149 * breaking up a circle into ModifySegmentDataType segments.
67150 */
67151ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX = 1;
67152
67153
67154/**
67155 * @param {ol.Feature} feature Feature.
67156 * @private
67157 */
67158ol.interaction.Modify.prototype.addFeature_ = function(feature) {
67159 var geometry = feature.getGeometry();
67160 if (geometry && geometry.getType() in this.SEGMENT_WRITERS_) {
67161 this.SEGMENT_WRITERS_[geometry.getType()].call(this, feature, geometry);
67162 }
67163 var map = this.getMap();
67164 if (map && map.isRendered() && this.getActive()) {
67165 this.handlePointerAtPixel_(this.lastPixel_, map);
67166 }
67167 ol.events.listen(feature, ol.events.EventType.CHANGE,
67168 this.handleFeatureChange_, this);
67169};
67170
67171
67172/**
67173 * @param {ol.MapBrowserPointerEvent} evt Map browser event
67174 * @private
67175 */
67176ol.interaction.Modify.prototype.willModifyFeatures_ = function(evt) {
67177 if (!this.modified_) {
67178 this.modified_ = true;
67179 this.dispatchEvent(new ol.interaction.Modify.Event(
67180 ol.interaction.ModifyEventType.MODIFYSTART, this.features_, evt));
67181 }
67182};
67183
67184
67185/**
67186 * @param {ol.Feature} feature Feature.
67187 * @private
67188 */
67189ol.interaction.Modify.prototype.removeFeature_ = function(feature) {
67190 this.removeFeatureSegmentData_(feature);
67191 // Remove the vertex feature if the collection of canditate features
67192 // is empty.
67193 if (this.vertexFeature_ && this.features_.getLength() === 0) {
67194 this.overlay_.getSource().removeFeature(this.vertexFeature_);
67195 this.vertexFeature_ = null;
67196 }
67197 ol.events.unlisten(feature, ol.events.EventType.CHANGE,
67198 this.handleFeatureChange_, this);
67199};
67200
67201
67202/**
67203 * @param {ol.Feature} feature Feature.
67204 * @private
67205 */
67206ol.interaction.Modify.prototype.removeFeatureSegmentData_ = function(feature) {
67207 var rBush = this.rBush_;
67208 var /** @type {Array.<ol.ModifySegmentDataType>} */ nodesToRemove = [];
67209 rBush.forEach(
67210 /**
67211 * @param {ol.ModifySegmentDataType} node RTree node.
67212 */
67213 function(node) {
67214 if (feature === node.feature) {
67215 nodesToRemove.push(node);
67216 }
67217 });
67218 for (var i = nodesToRemove.length - 1; i >= 0; --i) {
67219 rBush.remove(nodesToRemove[i]);
67220 }
67221};
67222
67223
67224/**
67225 * @inheritDoc
67226 */
67227ol.interaction.Modify.prototype.setActive = function(active) {
67228 if (this.vertexFeature_ && !active) {
67229 this.overlay_.getSource().removeFeature(this.vertexFeature_);
67230 this.vertexFeature_ = null;
67231 }
67232 ol.interaction.Pointer.prototype.setActive.call(this, active);
67233};
67234
67235
67236/**
67237 * @inheritDoc
67238 */
67239ol.interaction.Modify.prototype.setMap = function(map) {
67240 this.overlay_.setMap(map);
67241 ol.interaction.Pointer.prototype.setMap.call(this, map);
67242};
67243
67244
67245/**
67246 * @param {ol.source.Vector.Event} event Event.
67247 * @private
67248 */
67249ol.interaction.Modify.prototype.handleSourceAdd_ = function(event) {
67250 if (event.feature) {
67251 this.features_.push(event.feature);
67252 }
67253};
67254
67255
67256/**
67257 * @param {ol.source.Vector.Event} event Event.
67258 * @private
67259 */
67260ol.interaction.Modify.prototype.handleSourceRemove_ = function(event) {
67261 if (event.feature) {
67262 this.features_.remove(event.feature);
67263 }
67264};
67265
67266
67267/**
67268 * @param {ol.Collection.Event} evt Event.
67269 * @private
67270 */
67271ol.interaction.Modify.prototype.handleFeatureAdd_ = function(evt) {
67272 this.addFeature_(/** @type {ol.Feature} */ (evt.element));
67273};
67274
67275
67276/**
67277 * @param {ol.events.Event} evt Event.
67278 * @private
67279 */
67280ol.interaction.Modify.prototype.handleFeatureChange_ = function(evt) {
67281 if (!this.changingFeature_) {
67282 var feature = /** @type {ol.Feature} */ (evt.target);
67283 this.removeFeature_(feature);
67284 this.addFeature_(feature);
67285 }
67286};
67287
67288
67289/**
67290 * @param {ol.Collection.Event} evt Event.
67291 * @private
67292 */
67293ol.interaction.Modify.prototype.handleFeatureRemove_ = function(evt) {
67294 var feature = /** @type {ol.Feature} */ (evt.element);
67295 this.removeFeature_(feature);
67296};
67297
67298
67299/**
67300 * @param {ol.Feature} feature Feature
67301 * @param {ol.geom.Point} geometry Geometry.
67302 * @private
67303 */
67304ol.interaction.Modify.prototype.writePointGeometry_ = function(feature, geometry) {
67305 var coordinates = geometry.getCoordinates();
67306 var segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67307 feature: feature,
67308 geometry: geometry,
67309 segment: [coordinates, coordinates]
67310 });
67311 this.rBush_.insert(geometry.getExtent(), segmentData);
67312};
67313
67314
67315/**
67316 * @param {ol.Feature} feature Feature
67317 * @param {ol.geom.MultiPoint} geometry Geometry.
67318 * @private
67319 */
67320ol.interaction.Modify.prototype.writeMultiPointGeometry_ = function(feature, geometry) {
67321 var points = geometry.getCoordinates();
67322 var coordinates, i, ii, segmentData;
67323 for (i = 0, ii = points.length; i < ii; ++i) {
67324 coordinates = points[i];
67325 segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67326 feature: feature,
67327 geometry: geometry,
67328 depth: [i],
67329 index: i,
67330 segment: [coordinates, coordinates]
67331 });
67332 this.rBush_.insert(geometry.getExtent(), segmentData);
67333 }
67334};
67335
67336
67337/**
67338 * @param {ol.Feature} feature Feature
67339 * @param {ol.geom.LineString} geometry Geometry.
67340 * @private
67341 */
67342ol.interaction.Modify.prototype.writeLineStringGeometry_ = function(feature, geometry) {
67343 var coordinates = geometry.getCoordinates();
67344 var i, ii, segment, segmentData;
67345 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
67346 segment = coordinates.slice(i, i + 2);
67347 segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67348 feature: feature,
67349 geometry: geometry,
67350 index: i,
67351 segment: segment
67352 });
67353 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
67354 }
67355};
67356
67357
67358/**
67359 * @param {ol.Feature} feature Feature
67360 * @param {ol.geom.MultiLineString} geometry Geometry.
67361 * @private
67362 */
67363ol.interaction.Modify.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {
67364 var lines = geometry.getCoordinates();
67365 var coordinates, i, ii, j, jj, segment, segmentData;
67366 for (j = 0, jj = lines.length; j < jj; ++j) {
67367 coordinates = lines[j];
67368 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
67369 segment = coordinates.slice(i, i + 2);
67370 segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67371 feature: feature,
67372 geometry: geometry,
67373 depth: [j],
67374 index: i,
67375 segment: segment
67376 });
67377 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
67378 }
67379 }
67380};
67381
67382
67383/**
67384 * @param {ol.Feature} feature Feature
67385 * @param {ol.geom.Polygon} geometry Geometry.
67386 * @private
67387 */
67388ol.interaction.Modify.prototype.writePolygonGeometry_ = function(feature, geometry) {
67389 var rings = geometry.getCoordinates();
67390 var coordinates, i, ii, j, jj, segment, segmentData;
67391 for (j = 0, jj = rings.length; j < jj; ++j) {
67392 coordinates = rings[j];
67393 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
67394 segment = coordinates.slice(i, i + 2);
67395 segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67396 feature: feature,
67397 geometry: geometry,
67398 depth: [j],
67399 index: i,
67400 segment: segment
67401 });
67402 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
67403 }
67404 }
67405};
67406
67407
67408/**
67409 * @param {ol.Feature} feature Feature
67410 * @param {ol.geom.MultiPolygon} geometry Geometry.
67411 * @private
67412 */
67413ol.interaction.Modify.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {
67414 var polygons = geometry.getCoordinates();
67415 var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;
67416 for (k = 0, kk = polygons.length; k < kk; ++k) {
67417 rings = polygons[k];
67418 for (j = 0, jj = rings.length; j < jj; ++j) {
67419 coordinates = rings[j];
67420 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
67421 segment = coordinates.slice(i, i + 2);
67422 segmentData = /** @type {ol.ModifySegmentDataType} */ ({
67423 feature: feature,
67424 geometry: geometry,
67425 depth: [j, k],
67426 index: i,
67427 segment: segment
67428 });
67429 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
67430 }
67431 }
67432 }
67433};
67434
67435
67436/**
67437 * We convert a circle into two segments. The segment at index
67438 * {@link ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CENTER_INDEX} is the
67439 * circle's center (a point). The segment at index
67440 * {@link ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX} is
67441 * the circumference, and is not a line segment.
67442 *
67443 * @param {ol.Feature} feature Feature.
67444 * @param {ol.geom.Circle} geometry Geometry.
67445 * @private
67446 */
67447ol.interaction.Modify.prototype.writeCircleGeometry_ = function(feature, geometry) {
67448 var coordinates = geometry.getCenter();
67449 var centerSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
67450 feature: feature,
67451 geometry: geometry,
67452 index: ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CENTER_INDEX,
67453 segment: [coordinates, coordinates]
67454 });
67455 var circumferenceSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
67456 feature: feature,
67457 geometry: geometry,
67458 index: ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX,
67459 segment: [coordinates, coordinates]
67460 });
67461 var featureSegments = [centerSegmentData, circumferenceSegmentData];
67462 centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
67463 this.rBush_.insert(ol.extent.createOrUpdateFromCoordinate(coordinates), centerSegmentData);
67464 this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
67465};
67466
67467
67468/**
67469 * @param {ol.Feature} feature Feature
67470 * @param {ol.geom.GeometryCollection} geometry Geometry.
67471 * @private
67472 */
67473ol.interaction.Modify.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {
67474 var i, geometries = geometry.getGeometriesArray();
67475 for (i = 0; i < geometries.length; ++i) {
67476 this.SEGMENT_WRITERS_[geometries[i].getType()].call(
67477 this, feature, geometries[i]);
67478 }
67479};
67480
67481
67482/**
67483 * @param {ol.Coordinate} coordinates Coordinates.
67484 * @return {ol.Feature} Vertex feature.
67485 * @private
67486 */
67487ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = function(coordinates) {
67488 var vertexFeature = this.vertexFeature_;
67489 if (!vertexFeature) {
67490 vertexFeature = new ol.Feature(new ol.geom.Point(coordinates));
67491 this.vertexFeature_ = vertexFeature;
67492 this.overlay_.getSource().addFeature(vertexFeature);
67493 } else {
67494 var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
67495 geometry.setCoordinates(coordinates);
67496 }
67497 return vertexFeature;
67498};
67499
67500
67501/**
67502 * @param {ol.ModifySegmentDataType} a The first segment data.
67503 * @param {ol.ModifySegmentDataType} b The second segment data.
67504 * @return {number} The difference in indexes.
67505 * @private
67506 */
67507ol.interaction.Modify.compareIndexes_ = function(a, b) {
67508 return a.index - b.index;
67509};
67510
67511
67512/**
67513 * @param {ol.MapBrowserPointerEvent} evt Event.
67514 * @return {boolean} Start drag sequence?
67515 * @this {ol.interaction.Modify}
67516 * @private
67517 */
67518ol.interaction.Modify.handleDownEvent_ = function(evt) {
67519 if (!this.condition_(evt)) {
67520 return false;
67521 }
67522 this.handlePointerAtPixel_(evt.pixel, evt.map);
67523 var pixelCoordinate = evt.map.getCoordinateFromPixel(evt.pixel);
67524 this.dragSegments_.length = 0;
67525 this.modified_ = false;
67526 var vertexFeature = this.vertexFeature_;
67527 if (vertexFeature) {
67528 var insertVertices = [];
67529 var geometry = /** @type {ol.geom.Point} */ (vertexFeature.getGeometry());
67530 var vertex = geometry.getCoordinates();
67531 var vertexExtent = ol.extent.boundingExtent([vertex]);
67532 var segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
67533 var componentSegments = {};
67534 segmentDataMatches.sort(ol.interaction.Modify.compareIndexes_);
67535 for (var i = 0, ii = segmentDataMatches.length; i < ii; ++i) {
67536 var segmentDataMatch = segmentDataMatches[i];
67537 var segment = segmentDataMatch.segment;
67538 var uid = ol.getUid(segmentDataMatch.feature);
67539 var depth = segmentDataMatch.depth;
67540 if (depth) {
67541 uid += '-' + depth.join('-'); // separate feature components
67542 }
67543 if (!componentSegments[uid]) {
67544 componentSegments[uid] = new Array(2);
67545 }
67546 if (segmentDataMatch.geometry.getType() === ol.geom.GeometryType.CIRCLE &&
67547 segmentDataMatch.index === ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX) {
67548
67549 var closestVertex = ol.interaction.Modify.closestOnSegmentData_(pixelCoordinate, segmentDataMatch);
67550 if (ol.coordinate.equals(closestVertex, vertex) && !componentSegments[uid][0]) {
67551 this.dragSegments_.push([segmentDataMatch, 0]);
67552 componentSegments[uid][0] = segmentDataMatch;
67553 }
67554 } else if (ol.coordinate.equals(segment[0], vertex) &&
67555 !componentSegments[uid][0]) {
67556 this.dragSegments_.push([segmentDataMatch, 0]);
67557 componentSegments[uid][0] = segmentDataMatch;
67558 } else if (ol.coordinate.equals(segment[1], vertex) &&
67559 !componentSegments[uid][1]) {
67560
67561 // prevent dragging closed linestrings by the connecting node
67562 if ((segmentDataMatch.geometry.getType() ===
67563 ol.geom.GeometryType.LINE_STRING ||
67564 segmentDataMatch.geometry.getType() ===
67565 ol.geom.GeometryType.MULTI_LINE_STRING) &&
67566 componentSegments[uid][0] &&
67567 componentSegments[uid][0].index === 0) {
67568 continue;
67569 }
67570
67571 this.dragSegments_.push([segmentDataMatch, 1]);
67572 componentSegments[uid][1] = segmentDataMatch;
67573 } else if (this.insertVertexCondition_(evt) && ol.getUid(segment) in this.vertexSegments_ &&
67574 (!componentSegments[uid][0] && !componentSegments[uid][1])) {
67575 insertVertices.push([segmentDataMatch, vertex]);
67576 }
67577 }
67578 if (insertVertices.length) {
67579 this.willModifyFeatures_(evt);
67580 }
67581 for (var j = insertVertices.length - 1; j >= 0; --j) {
67582 this.insertVertex_.apply(this, insertVertices[j]);
67583 }
67584 }
67585 return !!this.vertexFeature_;
67586};
67587
67588
67589/**
67590 * @param {ol.MapBrowserPointerEvent} evt Event.
67591 * @this {ol.interaction.Modify}
67592 * @private
67593 */
67594ol.interaction.Modify.handleDragEvent_ = function(evt) {
67595 this.ignoreNextSingleClick_ = false;
67596 this.willModifyFeatures_(evt);
67597
67598 var vertex = evt.coordinate;
67599 for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
67600 var dragSegment = this.dragSegments_[i];
67601 var segmentData = dragSegment[0];
67602 var depth = segmentData.depth;
67603 var geometry = segmentData.geometry;
67604 var coordinates;
67605 var segment = segmentData.segment;
67606 var index = dragSegment[1];
67607
67608 while (vertex.length < geometry.getStride()) {
67609 vertex.push(segment[index][vertex.length]);
67610 }
67611
67612 switch (geometry.getType()) {
67613 case ol.geom.GeometryType.POINT:
67614 coordinates = vertex;
67615 segment[0] = segment[1] = vertex;
67616 break;
67617 case ol.geom.GeometryType.MULTI_POINT:
67618 coordinates = geometry.getCoordinates();
67619 coordinates[segmentData.index] = vertex;
67620 segment[0] = segment[1] = vertex;
67621 break;
67622 case ol.geom.GeometryType.LINE_STRING:
67623 coordinates = geometry.getCoordinates();
67624 coordinates[segmentData.index + index] = vertex;
67625 segment[index] = vertex;
67626 break;
67627 case ol.geom.GeometryType.MULTI_LINE_STRING:
67628 coordinates = geometry.getCoordinates();
67629 coordinates[depth[0]][segmentData.index + index] = vertex;
67630 segment[index] = vertex;
67631 break;
67632 case ol.geom.GeometryType.POLYGON:
67633 coordinates = geometry.getCoordinates();
67634 coordinates[depth[0]][segmentData.index + index] = vertex;
67635 segment[index] = vertex;
67636 break;
67637 case ol.geom.GeometryType.MULTI_POLYGON:
67638 coordinates = geometry.getCoordinates();
67639 coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
67640 segment[index] = vertex;
67641 break;
67642 case ol.geom.GeometryType.CIRCLE:
67643 segment[0] = segment[1] = vertex;
67644 if (segmentData.index === ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CENTER_INDEX) {
67645 this.changingFeature_ = true;
67646 geometry.setCenter(vertex);
67647 this.changingFeature_ = false;
67648 } else { // We're dragging the circle's circumference:
67649 this.changingFeature_ = true;
67650 geometry.setRadius(ol.coordinate.distance(geometry.getCenter(), vertex));
67651 this.changingFeature_ = false;
67652 }
67653 break;
67654 default:
67655 // pass
67656 }
67657
67658 if (coordinates) {
67659 this.setGeometryCoordinates_(geometry, coordinates);
67660 }
67661 }
67662 this.createOrUpdateVertexFeature_(vertex);
67663};
67664
67665
67666/**
67667 * @param {ol.MapBrowserPointerEvent} evt Event.
67668 * @return {boolean} Stop drag sequence?
67669 * @this {ol.interaction.Modify}
67670 * @private
67671 */
67672ol.interaction.Modify.handleUpEvent_ = function(evt) {
67673 var segmentData;
67674 var geometry;
67675 for (var i = this.dragSegments_.length - 1; i >= 0; --i) {
67676 segmentData = this.dragSegments_[i][0];
67677 geometry = segmentData.geometry;
67678 if (geometry.getType() === ol.geom.GeometryType.CIRCLE) {
67679 // Update a circle object in the R* bush:
67680 var coordinates = geometry.getCenter();
67681 var centerSegmentData = segmentData.featureSegments[0];
67682 var circumferenceSegmentData = segmentData.featureSegments[1];
67683 centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
67684 circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
67685 this.rBush_.update(ol.extent.createOrUpdateFromCoordinate(coordinates), centerSegmentData);
67686 this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
67687 } else {
67688 this.rBush_.update(ol.extent.boundingExtent(segmentData.segment),
67689 segmentData);
67690 }
67691 }
67692 if (this.modified_) {
67693 this.dispatchEvent(new ol.interaction.Modify.Event(
67694 ol.interaction.ModifyEventType.MODIFYEND, this.features_, evt));
67695 this.modified_ = false;
67696 }
67697 return false;
67698};
67699
67700
67701/**
67702 * Handles the {@link ol.MapBrowserEvent map browser event} and may modify the
67703 * geometry.
67704 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
67705 * @return {boolean} `false` to stop event propagation.
67706 * @this {ol.interaction.Modify}
67707 * @api
67708 */
67709ol.interaction.Modify.handleEvent = function(mapBrowserEvent) {
67710 if (!(mapBrowserEvent instanceof ol.MapBrowserPointerEvent)) {
67711 return true;
67712 }
67713 this.lastPointerEvent_ = mapBrowserEvent;
67714
67715 var handled;
67716 if (!mapBrowserEvent.map.getView().getHints()[ol.ViewHint.INTERACTING] &&
67717 mapBrowserEvent.type == ol.MapBrowserEventType.POINTERMOVE &&
67718 !this.handlingDownUpSequence) {
67719 this.handlePointerMove_(mapBrowserEvent);
67720 }
67721 if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) {
67722 if (mapBrowserEvent.type != ol.MapBrowserEventType.SINGLECLICK ||
67723 !this.ignoreNextSingleClick_) {
67724 handled = this.removePoint();
67725 } else {
67726 handled = true;
67727 }
67728 }
67729
67730 if (mapBrowserEvent.type == ol.MapBrowserEventType.SINGLECLICK) {
67731 this.ignoreNextSingleClick_ = false;
67732 }
67733
67734 return ol.interaction.Pointer.handleEvent.call(this, mapBrowserEvent) &&
67735 !handled;
67736};
67737
67738
67739/**
67740 * @param {ol.MapBrowserEvent} evt Event.
67741 * @private
67742 */
67743ol.interaction.Modify.prototype.handlePointerMove_ = function(evt) {
67744 this.lastPixel_ = evt.pixel;
67745 this.handlePointerAtPixel_(evt.pixel, evt.map);
67746};
67747
67748
67749/**
67750 * @param {ol.Pixel} pixel Pixel
67751 * @param {ol.Map} map Map.
67752 * @private
67753 */
67754ol.interaction.Modify.prototype.handlePointerAtPixel_ = function(pixel, map) {
67755 var pixelCoordinate = map.getCoordinateFromPixel(pixel);
67756 var sortByDistance = function(a, b) {
67757 return ol.interaction.Modify.pointDistanceToSegmentDataSquared_(pixelCoordinate, a) -
67758 ol.interaction.Modify.pointDistanceToSegmentDataSquared_(pixelCoordinate, b);
67759 };
67760
67761 var box = ol.extent.buffer(
67762 ol.extent.createOrUpdateFromCoordinate(pixelCoordinate),
67763 map.getView().getResolution() * this.pixelTolerance_);
67764
67765 var rBush = this.rBush_;
67766 var nodes = rBush.getInExtent(box);
67767 if (nodes.length > 0) {
67768 nodes.sort(sortByDistance);
67769 var node = nodes[0];
67770 var closestSegment = node.segment;
67771 var vertex = ol.interaction.Modify.closestOnSegmentData_(pixelCoordinate, node);
67772 var vertexPixel = map.getPixelFromCoordinate(vertex);
67773 var dist = ol.coordinate.distance(pixel, vertexPixel);
67774 if (dist <= this.pixelTolerance_) {
67775 var vertexSegments = {};
67776
67777 if (node.geometry.getType() === ol.geom.GeometryType.CIRCLE &&
67778 node.index === ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX) {
67779
67780 this.snappedToVertex_ = true;
67781 this.createOrUpdateVertexFeature_(vertex);
67782 } else {
67783 var pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
67784 var pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
67785 var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
67786 var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
67787 dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
67788 this.snappedToVertex_ = dist <= this.pixelTolerance_;
67789 if (this.snappedToVertex_) {
67790 vertex = squaredDist1 > squaredDist2 ?
67791 closestSegment[1] : closestSegment[0];
67792 }
67793 this.createOrUpdateVertexFeature_(vertex);
67794 var segment;
67795 for (var i = 1, ii = nodes.length; i < ii; ++i) {
67796 segment = nodes[i].segment;
67797 if ((ol.coordinate.equals(closestSegment[0], segment[0]) &&
67798 ol.coordinate.equals(closestSegment[1], segment[1]) ||
67799 (ol.coordinate.equals(closestSegment[0], segment[1]) &&
67800 ol.coordinate.equals(closestSegment[1], segment[0])))) {
67801 vertexSegments[ol.getUid(segment)] = true;
67802 } else {
67803 break;
67804 }
67805 }
67806 }
67807
67808 vertexSegments[ol.getUid(closestSegment)] = true;
67809 this.vertexSegments_ = vertexSegments;
67810 return;
67811 }
67812 }
67813 if (this.vertexFeature_) {
67814 this.overlay_.getSource().removeFeature(this.vertexFeature_);
67815 this.vertexFeature_ = null;
67816 }
67817};
67818
67819
67820/**
67821 * Returns the distance from a point to a line segment.
67822 *
67823 * @param {ol.Coordinate} pointCoordinates The coordinates of the point from
67824 * which to calculate the distance.
67825 * @param {ol.ModifySegmentDataType} segmentData The object describing the line
67826 * segment we are calculating the distance to.
67827 * @return {number} The square of the distance between a point and a line segment.
67828 */
67829ol.interaction.Modify.pointDistanceToSegmentDataSquared_ = function(pointCoordinates, segmentData) {
67830 var geometry = segmentData.geometry;
67831
67832 if (geometry.getType() === ol.geom.GeometryType.CIRCLE) {
67833 var circleGeometry = /** @type {ol.geom.Circle} */ (geometry);
67834
67835 if (segmentData.index === ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX) {
67836 var distanceToCenterSquared =
67837 ol.coordinate.squaredDistance(circleGeometry.getCenter(), pointCoordinates);
67838 var distanceToCircumference =
67839 Math.sqrt(distanceToCenterSquared) - circleGeometry.getRadius();
67840 return distanceToCircumference * distanceToCircumference;
67841 }
67842 }
67843 return ol.coordinate.squaredDistanceToSegment(pointCoordinates, segmentData.segment);
67844};
67845
67846/**
67847 * Returns the point closest to a given line segment.
67848 *
67849 * @param {ol.Coordinate} pointCoordinates The point to which a closest point
67850 * should be found.
67851 * @param {ol.ModifySegmentDataType} segmentData The object describing the line
67852 * segment which should contain the closest point.
67853 * @return {ol.Coordinate} The point closest to the specified line segment.
67854 */
67855ol.interaction.Modify.closestOnSegmentData_ = function(pointCoordinates, segmentData) {
67856 var geometry = segmentData.geometry;
67857
67858 if (geometry.getType() === ol.geom.GeometryType.CIRCLE &&
67859 segmentData.index === ol.interaction.Modify.MODIFY_SEGMENT_CIRCLE_CIRCUMFERENCE_INDEX) {
67860 return geometry.getClosestPoint(pointCoordinates);
67861 }
67862 return ol.coordinate.closestOnSegment(pointCoordinates, segmentData.segment);
67863};
67864
67865
67866/**
67867 * @param {ol.ModifySegmentDataType} segmentData Segment data.
67868 * @param {ol.Coordinate} vertex Vertex.
67869 * @private
67870 */
67871ol.interaction.Modify.prototype.insertVertex_ = function(segmentData, vertex) {
67872 var segment = segmentData.segment;
67873 var feature = segmentData.feature;
67874 var geometry = segmentData.geometry;
67875 var depth = segmentData.depth;
67876 var index = /** @type {number} */ (segmentData.index);
67877 var coordinates;
67878
67879 while (vertex.length < geometry.getStride()) {
67880 vertex.push(0);
67881 }
67882
67883 switch (geometry.getType()) {
67884 case ol.geom.GeometryType.MULTI_LINE_STRING:
67885 coordinates = geometry.getCoordinates();
67886 coordinates[depth[0]].splice(index + 1, 0, vertex);
67887 break;
67888 case ol.geom.GeometryType.POLYGON:
67889 coordinates = geometry.getCoordinates();
67890 coordinates[depth[0]].splice(index + 1, 0, vertex);
67891 break;
67892 case ol.geom.GeometryType.MULTI_POLYGON:
67893 coordinates = geometry.getCoordinates();
67894 coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex);
67895 break;
67896 case ol.geom.GeometryType.LINE_STRING:
67897 coordinates = geometry.getCoordinates();
67898 coordinates.splice(index + 1, 0, vertex);
67899 break;
67900 default:
67901 return;
67902 }
67903
67904 this.setGeometryCoordinates_(geometry, coordinates);
67905 var rTree = this.rBush_;
67906 rTree.remove(segmentData);
67907 this.updateSegmentIndices_(geometry, index, depth, 1);
67908 var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
67909 segment: [segment[0], vertex],
67910 feature: feature,
67911 geometry: geometry,
67912 depth: depth,
67913 index: index
67914 });
67915 rTree.insert(ol.extent.boundingExtent(newSegmentData.segment),
67916 newSegmentData);
67917 this.dragSegments_.push([newSegmentData, 1]);
67918
67919 var newSegmentData2 = /** @type {ol.ModifySegmentDataType} */ ({
67920 segment: [vertex, segment[1]],
67921 feature: feature,
67922 geometry: geometry,
67923 depth: depth,
67924 index: index + 1
67925 });
67926 rTree.insert(ol.extent.boundingExtent(newSegmentData2.segment),
67927 newSegmentData2);
67928 this.dragSegments_.push([newSegmentData2, 0]);
67929 this.ignoreNextSingleClick_ = true;
67930};
67931
67932/**
67933 * Removes the vertex currently being pointed.
67934 * @return {boolean} True when a vertex was removed.
67935 * @api
67936 */
67937ol.interaction.Modify.prototype.removePoint = function() {
67938 if (this.lastPointerEvent_ && this.lastPointerEvent_.type != ol.MapBrowserEventType.POINTERDRAG) {
67939 var evt = this.lastPointerEvent_;
67940 this.willModifyFeatures_(evt);
67941 this.removeVertex_();
67942 this.dispatchEvent(new ol.interaction.Modify.Event(
67943 ol.interaction.ModifyEventType.MODIFYEND, this.features_, evt));
67944 this.modified_ = false;
67945 return true;
67946 }
67947 return false;
67948};
67949
67950/**
67951 * Removes a vertex from all matching features.
67952 * @return {boolean} True when a vertex was removed.
67953 * @private
67954 */
67955ol.interaction.Modify.prototype.removeVertex_ = function() {
67956 var dragSegments = this.dragSegments_;
67957 var segmentsByFeature = {};
67958 var deleted = false;
67959 var component, coordinates, dragSegment, geometry, i, index, left;
67960 var newIndex, right, segmentData, uid;
67961 for (i = dragSegments.length - 1; i >= 0; --i) {
67962 dragSegment = dragSegments[i];
67963 segmentData = dragSegment[0];
67964 uid = ol.getUid(segmentData.feature);
67965 if (segmentData.depth) {
67966 // separate feature components
67967 uid += '-' + segmentData.depth.join('-');
67968 }
67969 if (!(uid in segmentsByFeature)) {
67970 segmentsByFeature[uid] = {};
67971 }
67972 if (dragSegment[1] === 0) {
67973 segmentsByFeature[uid].right = segmentData;
67974 segmentsByFeature[uid].index = segmentData.index;
67975 } else if (dragSegment[1] == 1) {
67976 segmentsByFeature[uid].left = segmentData;
67977 segmentsByFeature[uid].index = segmentData.index + 1;
67978 }
67979
67980 }
67981 for (uid in segmentsByFeature) {
67982 right = segmentsByFeature[uid].right;
67983 left = segmentsByFeature[uid].left;
67984 index = segmentsByFeature[uid].index;
67985 newIndex = index - 1;
67986 if (left !== undefined) {
67987 segmentData = left;
67988 } else {
67989 segmentData = right;
67990 }
67991 if (newIndex < 0) {
67992 newIndex = 0;
67993 }
67994 geometry = segmentData.geometry;
67995 coordinates = geometry.getCoordinates();
67996 component = coordinates;
67997 deleted = false;
67998 switch (geometry.getType()) {
67999 case ol.geom.GeometryType.MULTI_LINE_STRING:
68000 if (coordinates[segmentData.depth[0]].length > 2) {
68001 coordinates[segmentData.depth[0]].splice(index, 1);
68002 deleted = true;
68003 }
68004 break;
68005 case ol.geom.GeometryType.LINE_STRING:
68006 if (coordinates.length > 2) {
68007 coordinates.splice(index, 1);
68008 deleted = true;
68009 }
68010 break;
68011 case ol.geom.GeometryType.MULTI_POLYGON:
68012 component = component[segmentData.depth[1]];
68013 /* falls through */
68014 case ol.geom.GeometryType.POLYGON:
68015 component = component[segmentData.depth[0]];
68016 if (component.length > 4) {
68017 if (index == component.length - 1) {
68018 index = 0;
68019 }
68020 component.splice(index, 1);
68021 deleted = true;
68022 if (index === 0) {
68023 // close the ring again
68024 component.pop();
68025 component.push(component[0]);
68026 newIndex = component.length - 1;
68027 }
68028 }
68029 break;
68030 default:
68031 // pass
68032 }
68033
68034 if (deleted) {
68035 this.setGeometryCoordinates_(geometry, coordinates);
68036 var segments = [];
68037 if (left !== undefined) {
68038 this.rBush_.remove(left);
68039 segments.push(left.segment[0]);
68040 }
68041 if (right !== undefined) {
68042 this.rBush_.remove(right);
68043 segments.push(right.segment[1]);
68044 }
68045 if (left !== undefined && right !== undefined) {
68046 var newSegmentData = /** @type {ol.ModifySegmentDataType} */ ({
68047 depth: segmentData.depth,
68048 feature: segmentData.feature,
68049 geometry: segmentData.geometry,
68050 index: newIndex,
68051 segment: segments
68052 });
68053 this.rBush_.insert(ol.extent.boundingExtent(newSegmentData.segment),
68054 newSegmentData);
68055 }
68056 this.updateSegmentIndices_(geometry, index, segmentData.depth, -1);
68057 if (this.vertexFeature_) {
68058 this.overlay_.getSource().removeFeature(this.vertexFeature_);
68059 this.vertexFeature_ = null;
68060 }
68061 dragSegments.length = 0;
68062 }
68063
68064 }
68065 return deleted;
68066};
68067
68068
68069/**
68070 * @param {ol.geom.SimpleGeometry} geometry Geometry.
68071 * @param {Array} coordinates Coordinates.
68072 * @private
68073 */
68074ol.interaction.Modify.prototype.setGeometryCoordinates_ = function(geometry, coordinates) {
68075 this.changingFeature_ = true;
68076 geometry.setCoordinates(coordinates);
68077 this.changingFeature_ = false;
68078};
68079
68080
68081/**
68082 * @param {ol.geom.SimpleGeometry} geometry Geometry.
68083 * @param {number} index Index.
68084 * @param {Array.<number>|undefined} depth Depth.
68085 * @param {number} delta Delta (1 or -1).
68086 * @private
68087 */
68088ol.interaction.Modify.prototype.updateSegmentIndices_ = function(
68089 geometry, index, depth, delta) {
68090 this.rBush_.forEachInExtent(geometry.getExtent(), function(segmentDataMatch) {
68091 if (segmentDataMatch.geometry === geometry &&
68092 (depth === undefined || segmentDataMatch.depth === undefined ||
68093 ol.array.equals(segmentDataMatch.depth, depth)) &&
68094 segmentDataMatch.index > index) {
68095 segmentDataMatch.index += delta;
68096 }
68097 });
68098};
68099
68100
68101/**
68102 * @return {ol.StyleFunction} Styles.
68103 */
68104ol.interaction.Modify.getDefaultStyleFunction = function() {
68105 var style = ol.style.Style.createDefaultEditing();
68106 return function(feature, resolution) {
68107 return style[ol.geom.GeometryType.POINT];
68108 };
68109};
68110
68111
68112/**
68113 * @classdesc
68114 * Events emitted by {@link ol.interaction.Modify} instances are instances of
68115 * this type.
68116 *
68117 * @constructor
68118 * @extends {ol.events.Event}
68119 * @implements {oli.ModifyEvent}
68120 * @param {ol.interaction.ModifyEventType} type Type.
68121 * @param {ol.Collection.<ol.Feature>} features The features modified.
68122 * @param {ol.MapBrowserPointerEvent} mapBrowserPointerEvent Associated
68123 * {@link ol.MapBrowserPointerEvent}.
68124 */
68125ol.interaction.Modify.Event = function(type, features, mapBrowserPointerEvent) {
68126
68127 ol.events.Event.call(this, type);
68128
68129 /**
68130 * The features being modified.
68131 * @type {ol.Collection.<ol.Feature>}
68132 * @api
68133 */
68134 this.features = features;
68135
68136 /**
68137 * Associated {@link ol.MapBrowserEvent}.
68138 * @type {ol.MapBrowserEvent}
68139 * @api
68140 */
68141 this.mapBrowserEvent = mapBrowserPointerEvent;
68142};
68143ol.inherits(ol.interaction.Modify.Event, ol.events.Event);
68144
68145goog.provide('ol.interaction.Select');
68146
68147goog.require('ol');
68148goog.require('ol.CollectionEventType');
68149goog.require('ol.array');
68150goog.require('ol.events');
68151goog.require('ol.events.Event');
68152goog.require('ol.events.condition');
68153goog.require('ol.functions');
68154goog.require('ol.geom.GeometryType');
68155goog.require('ol.interaction.Interaction');
68156goog.require('ol.layer.Vector');
68157goog.require('ol.obj');
68158goog.require('ol.source.Vector');
68159goog.require('ol.style.Style');
68160
68161
68162/**
68163 * @classdesc
68164 * Interaction for selecting vector features. By default, selected features are
68165 * styled differently, so this interaction can be used for visual highlighting,
68166 * as well as selecting features for other actions, such as modification or
68167 * output. There are three ways of controlling which features are selected:
68168 * using the browser event as defined by the `condition` and optionally the
68169 * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a
68170 * further feature filter using the `filter` option.
68171 *
68172 * Selected features are added to an internal unmanaged layer.
68173 *
68174 * @constructor
68175 * @extends {ol.interaction.Interaction}
68176 * @param {olx.interaction.SelectOptions=} opt_options Options.
68177 * @fires ol.interaction.Select.Event
68178 * @api
68179 */
68180ol.interaction.Select = function(opt_options) {
68181
68182 ol.interaction.Interaction.call(this, {
68183 handleEvent: ol.interaction.Select.handleEvent
68184 });
68185
68186 var options = opt_options ? opt_options : {};
68187
68188 /**
68189 * @private
68190 * @type {ol.EventsConditionType}
68191 */
68192 this.condition_ = options.condition ?
68193 options.condition : ol.events.condition.singleClick;
68194
68195 /**
68196 * @private
68197 * @type {ol.EventsConditionType}
68198 */
68199 this.addCondition_ = options.addCondition ?
68200 options.addCondition : ol.events.condition.never;
68201
68202 /**
68203 * @private
68204 * @type {ol.EventsConditionType}
68205 */
68206 this.removeCondition_ = options.removeCondition ?
68207 options.removeCondition : ol.events.condition.never;
68208
68209 /**
68210 * @private
68211 * @type {ol.EventsConditionType}
68212 */
68213 this.toggleCondition_ = options.toggleCondition ?
68214 options.toggleCondition : ol.events.condition.shiftKeyOnly;
68215
68216 /**
68217 * @private
68218 * @type {boolean}
68219 */
68220 this.multi_ = options.multi ? options.multi : false;
68221
68222 /**
68223 * @private
68224 * @type {ol.SelectFilterFunction}
68225 */
68226 this.filter_ = options.filter ? options.filter :
68227 ol.functions.TRUE;
68228
68229 /**
68230 * @private
68231 * @type {number}
68232 */
68233 this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;
68234
68235 var featureOverlay = new ol.layer.Vector({
68236 source: new ol.source.Vector({
68237 useSpatialIndex: false,
68238 features: options.features,
68239 wrapX: options.wrapX
68240 }),
68241 style: options.style ? options.style :
68242 ol.interaction.Select.getDefaultStyleFunction(),
68243 updateWhileAnimating: true,
68244 updateWhileInteracting: true
68245 });
68246
68247 /**
68248 * @private
68249 * @type {ol.layer.Vector}
68250 */
68251 this.featureOverlay_ = featureOverlay;
68252
68253 /** @type {function(ol.layer.Layer): boolean} */
68254 var layerFilter;
68255 if (options.layers) {
68256 if (typeof options.layers === 'function') {
68257 layerFilter = options.layers;
68258 } else {
68259 var layers = options.layers;
68260 layerFilter = function(layer) {
68261 return ol.array.includes(layers, layer);
68262 };
68263 }
68264 } else {
68265 layerFilter = ol.functions.TRUE;
68266 }
68267
68268 /**
68269 * @private
68270 * @type {function(ol.layer.Layer): boolean}
68271 */
68272 this.layerFilter_ = layerFilter;
68273
68274 /**
68275 * An association between selected feature (key)
68276 * and layer (value)
68277 * @private
68278 * @type {Object.<number, ol.layer.Layer>}
68279 */
68280 this.featureLayerAssociation_ = {};
68281
68282 var features = this.featureOverlay_.getSource().getFeaturesCollection();
68283 ol.events.listen(features, ol.CollectionEventType.ADD,
68284 this.addFeature_, this);
68285 ol.events.listen(features, ol.CollectionEventType.REMOVE,
68286 this.removeFeature_, this);
68287
68288};
68289ol.inherits(ol.interaction.Select, ol.interaction.Interaction);
68290
68291
68292/**
68293 * @param {ol.Feature|ol.render.Feature} feature Feature.
68294 * @param {ol.layer.Layer} layer Layer.
68295 * @private
68296 */
68297ol.interaction.Select.prototype.addFeatureLayerAssociation_ = function(feature, layer) {
68298 var key = ol.getUid(feature);
68299 this.featureLayerAssociation_[key] = layer;
68300};
68301
68302
68303/**
68304 * Get the selected features.
68305 * @return {ol.Collection.<ol.Feature>} Features collection.
68306 * @api
68307 */
68308ol.interaction.Select.prototype.getFeatures = function() {
68309 return this.featureOverlay_.getSource().getFeaturesCollection();
68310};
68311
68312
68313/**
68314 * Returns the Hit-detection tolerance.
68315 * @returns {number} Hit tolerance in pixels.
68316 * @api
68317 */
68318ol.interaction.Select.prototype.getHitTolerance = function() {
68319 return this.hitTolerance_;
68320};
68321
68322
68323/**
68324 * Returns the associated {@link ol.layer.Vector vectorlayer} of
68325 * the (last) selected feature. Note that this will not work with any
68326 * programmatic method like pushing features to
68327 * {@link ol.interaction.Select#getFeatures collection}.
68328 * @param {ol.Feature|ol.render.Feature} feature Feature
68329 * @return {ol.layer.Vector} Layer.
68330 * @api
68331 */
68332ol.interaction.Select.prototype.getLayer = function(feature) {
68333 var key = ol.getUid(feature);
68334 return /** @type {ol.layer.Vector} */ (this.featureLayerAssociation_[key]);
68335};
68336
68337
68338/**
68339 * Handles the {@link ol.MapBrowserEvent map browser event} and may change the
68340 * selected state of features.
68341 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
68342 * @return {boolean} `false` to stop event propagation.
68343 * @this {ol.interaction.Select}
68344 * @api
68345 */
68346ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
68347 if (!this.condition_(mapBrowserEvent)) {
68348 return true;
68349 }
68350 var add = this.addCondition_(mapBrowserEvent);
68351 var remove = this.removeCondition_(mapBrowserEvent);
68352 var toggle = this.toggleCondition_(mapBrowserEvent);
68353 var set = !add && !remove && !toggle;
68354 var map = mapBrowserEvent.map;
68355 var features = this.featureOverlay_.getSource().getFeaturesCollection();
68356 var deselected = [];
68357 var selected = [];
68358 if (set) {
68359 // Replace the currently selected feature(s) with the feature(s) at the
68360 // pixel, or clear the selected feature(s) if there is no feature at
68361 // the pixel.
68362 ol.obj.clear(this.featureLayerAssociation_);
68363 map.forEachFeatureAtPixel(mapBrowserEvent.pixel,
68364 (
68365 /**
68366 * @param {ol.Feature|ol.render.Feature} feature Feature.
68367 * @param {ol.layer.Layer} layer Layer.
68368 * @return {boolean|undefined} Continue to iterate over the features.
68369 */
68370 function(feature, layer) {
68371 if (this.filter_(feature, layer)) {
68372 selected.push(feature);
68373 this.addFeatureLayerAssociation_(feature, layer);
68374 return !this.multi_;
68375 }
68376 }).bind(this), {
68377 layerFilter: this.layerFilter_,
68378 hitTolerance: this.hitTolerance_
68379 });
68380 var i;
68381 for (i = features.getLength() - 1; i >= 0; --i) {
68382 var feature = features.item(i);
68383 var index = selected.indexOf(feature);
68384 if (index > -1) {
68385 // feature is already selected
68386 selected.splice(index, 1);
68387 } else {
68388 features.remove(feature);
68389 deselected.push(feature);
68390 }
68391 }
68392 if (selected.length !== 0) {
68393 features.extend(selected);
68394 }
68395 } else {
68396 // Modify the currently selected feature(s).
68397 map.forEachFeatureAtPixel(mapBrowserEvent.pixel,
68398 (
68399 /**
68400 * @param {ol.Feature|ol.render.Feature} feature Feature.
68401 * @param {ol.layer.Layer} layer Layer.
68402 * @return {boolean|undefined} Continue to iterate over the features.
68403 */
68404 function(feature, layer) {
68405 if (this.filter_(feature, layer)) {
68406 if ((add || toggle) &&
68407 !ol.array.includes(features.getArray(), feature)) {
68408 selected.push(feature);
68409 this.addFeatureLayerAssociation_(feature, layer);
68410 } else if ((remove || toggle) &&
68411 ol.array.includes(features.getArray(), feature)) {
68412 deselected.push(feature);
68413 this.removeFeatureLayerAssociation_(feature);
68414 }
68415 return !this.multi_;
68416 }
68417 }).bind(this), {
68418 layerFilter: this.layerFilter_,
68419 hitTolerance: this.hitTolerance_
68420 });
68421 var j;
68422 for (j = deselected.length - 1; j >= 0; --j) {
68423 features.remove(deselected[j]);
68424 }
68425 features.extend(selected);
68426 }
68427 if (selected.length > 0 || deselected.length > 0) {
68428 this.dispatchEvent(
68429 new ol.interaction.Select.Event(ol.interaction.Select.EventType_.SELECT,
68430 selected, deselected, mapBrowserEvent));
68431 }
68432 return ol.events.condition.pointerMove(mapBrowserEvent);
68433};
68434
68435
68436/**
68437 * Hit-detection tolerance. Pixels inside the radius around the given position
68438 * will be checked for features. This only works for the canvas renderer and
68439 * not for WebGL.
68440 * @param {number} hitTolerance Hit tolerance in pixels.
68441 * @api
68442 */
68443ol.interaction.Select.prototype.setHitTolerance = function(hitTolerance) {
68444 this.hitTolerance_ = hitTolerance;
68445};
68446
68447
68448/**
68449 * Remove the interaction from its current map, if any, and attach it to a new
68450 * map, if any. Pass `null` to just remove the interaction from the current map.
68451 * @param {ol.Map} map Map.
68452 * @override
68453 * @api
68454 */
68455ol.interaction.Select.prototype.setMap = function(map) {
68456 var currentMap = this.getMap();
68457 var selectedFeatures =
68458 this.featureOverlay_.getSource().getFeaturesCollection();
68459 if (currentMap) {
68460 selectedFeatures.forEach(currentMap.unskipFeature, currentMap);
68461 }
68462 ol.interaction.Interaction.prototype.setMap.call(this, map);
68463 this.featureOverlay_.setMap(map);
68464 if (map) {
68465 selectedFeatures.forEach(map.skipFeature, map);
68466 }
68467};
68468
68469
68470/**
68471 * @return {ol.StyleFunction} Styles.
68472 */
68473ol.interaction.Select.getDefaultStyleFunction = function() {
68474 var styles = ol.style.Style.createDefaultEditing();
68475 ol.array.extend(styles[ol.geom.GeometryType.POLYGON],
68476 styles[ol.geom.GeometryType.LINE_STRING]);
68477 ol.array.extend(styles[ol.geom.GeometryType.GEOMETRY_COLLECTION],
68478 styles[ol.geom.GeometryType.LINE_STRING]);
68479
68480 return function(feature, resolution) {
68481 if (!feature.getGeometry()) {
68482 return null;
68483 }
68484 return styles[feature.getGeometry().getType()];
68485 };
68486};
68487
68488
68489/**
68490 * @param {ol.Collection.Event} evt Event.
68491 * @private
68492 */
68493ol.interaction.Select.prototype.addFeature_ = function(evt) {
68494 var map = this.getMap();
68495 if (map) {
68496 map.skipFeature(/** @type {ol.Feature} */ (evt.element));
68497 }
68498};
68499
68500
68501/**
68502 * @param {ol.Collection.Event} evt Event.
68503 * @private
68504 */
68505ol.interaction.Select.prototype.removeFeature_ = function(evt) {
68506 var map = this.getMap();
68507 if (map) {
68508 map.unskipFeature(/** @type {ol.Feature} */ (evt.element));
68509 }
68510};
68511
68512
68513/**
68514 * @param {ol.Feature|ol.render.Feature} feature Feature.
68515 * @private
68516 */
68517ol.interaction.Select.prototype.removeFeatureLayerAssociation_ = function(feature) {
68518 var key = ol.getUid(feature);
68519 delete this.featureLayerAssociation_[key];
68520};
68521
68522
68523/**
68524 * @classdesc
68525 * Events emitted by {@link ol.interaction.Select} instances are instances of
68526 * this type.
68527 *
68528 * @param {ol.interaction.Select.EventType_} type The event type.
68529 * @param {Array.<ol.Feature>} selected Selected features.
68530 * @param {Array.<ol.Feature>} deselected Deselected features.
68531 * @param {ol.MapBrowserEvent} mapBrowserEvent Associated
68532 * {@link ol.MapBrowserEvent}.
68533 * @implements {oli.SelectEvent}
68534 * @extends {ol.events.Event}
68535 * @constructor
68536 */
68537ol.interaction.Select.Event = function(type, selected, deselected, mapBrowserEvent) {
68538 ol.events.Event.call(this, type);
68539
68540 /**
68541 * Selected features array.
68542 * @type {Array.<ol.Feature>}
68543 * @api
68544 */
68545 this.selected = selected;
68546
68547 /**
68548 * Deselected features array.
68549 * @type {Array.<ol.Feature>}
68550 * @api
68551 */
68552 this.deselected = deselected;
68553
68554 /**
68555 * Associated {@link ol.MapBrowserEvent}.
68556 * @type {ol.MapBrowserEvent}
68557 * @api
68558 */
68559 this.mapBrowserEvent = mapBrowserEvent;
68560};
68561ol.inherits(ol.interaction.Select.Event, ol.events.Event);
68562
68563
68564/**
68565 * @enum {string}
68566 * @private
68567 */
68568ol.interaction.Select.EventType_ = {
68569 /**
68570 * Triggered when feature(s) has been (de)selected.
68571 * @event ol.interaction.Select.Event#select
68572 * @api
68573 */
68574 SELECT: 'select'
68575};
68576
68577goog.provide('ol.interaction.Snap');
68578
68579goog.require('ol');
68580goog.require('ol.Collection');
68581goog.require('ol.CollectionEventType');
68582goog.require('ol.coordinate');
68583goog.require('ol.events');
68584goog.require('ol.events.EventType');
68585goog.require('ol.extent');
68586goog.require('ol.functions');
68587goog.require('ol.geom.GeometryType');
68588goog.require('ol.geom.Polygon');
68589goog.require('ol.interaction.Pointer');
68590goog.require('ol.obj');
68591goog.require('ol.source.Vector');
68592goog.require('ol.source.VectorEventType');
68593goog.require('ol.structs.RBush');
68594
68595
68596/**
68597 * @classdesc
68598 * Handles snapping of vector features while modifying or drawing them. The
68599 * features can come from a {@link ol.source.Vector} or {@link ol.Collection}
68600 * Any interaction object that allows the user to interact
68601 * with the features using the mouse can benefit from the snapping, as long
68602 * as it is added before.
68603 *
68604 * The snap interaction modifies map browser event `coordinate` and `pixel`
68605 * properties to force the snap to occur to any interaction that them.
68606 *
68607 * Example:
68608 *
68609 * var snap = new ol.interaction.Snap({
68610 * source: source
68611 * });
68612 *
68613 * @constructor
68614 * @extends {ol.interaction.Pointer}
68615 * @param {olx.interaction.SnapOptions=} opt_options Options.
68616 * @api
68617 */
68618ol.interaction.Snap = function(opt_options) {
68619
68620 ol.interaction.Pointer.call(this, {
68621 handleEvent: ol.interaction.Snap.handleEvent_,
68622 handleDownEvent: ol.functions.TRUE,
68623 handleUpEvent: ol.interaction.Snap.handleUpEvent_
68624 });
68625
68626 var options = opt_options ? opt_options : {};
68627
68628 /**
68629 * @type {ol.source.Vector}
68630 * @private
68631 */
68632 this.source_ = options.source ? options.source : null;
68633
68634 /**
68635 * @private
68636 * @type {boolean}
68637 */
68638 this.vertex_ = options.vertex !== undefined ? options.vertex : true;
68639
68640 /**
68641 * @private
68642 * @type {boolean}
68643 */
68644 this.edge_ = options.edge !== undefined ? options.edge : true;
68645
68646 /**
68647 * @type {ol.Collection.<ol.Feature>}
68648 * @private
68649 */
68650 this.features_ = options.features ? options.features : null;
68651
68652 /**
68653 * @type {Array.<ol.EventsKey>}
68654 * @private
68655 */
68656 this.featuresListenerKeys_ = [];
68657
68658 /**
68659 * @type {Object.<number, ol.EventsKey>}
68660 * @private
68661 */
68662 this.featureChangeListenerKeys_ = {};
68663
68664 /**
68665 * Extents are preserved so indexed segment can be quickly removed
68666 * when its feature geometry changes
68667 * @type {Object.<number, ol.Extent>}
68668 * @private
68669 */
68670 this.indexedFeaturesExtents_ = {};
68671
68672 /**
68673 * If a feature geometry changes while a pointer drag|move event occurs, the
68674 * feature doesn't get updated right away. It will be at the next 'pointerup'
68675 * event fired.
68676 * @type {Object.<number, ol.Feature>}
68677 * @private
68678 */
68679 this.pendingFeatures_ = {};
68680
68681 /**
68682 * Used for distance sorting in sortByDistance_
68683 * @type {ol.Coordinate}
68684 * @private
68685 */
68686 this.pixelCoordinate_ = null;
68687
68688 /**
68689 * @type {number}
68690 * @private
68691 */
68692 this.pixelTolerance_ = options.pixelTolerance !== undefined ?
68693 options.pixelTolerance : 10;
68694
68695 /**
68696 * @type {function(ol.SnapSegmentDataType, ol.SnapSegmentDataType): number}
68697 * @private
68698 */
68699 this.sortByDistance_ = ol.interaction.Snap.sortByDistance.bind(this);
68700
68701
68702 /**
68703 * Segment RTree for each layer
68704 * @type {ol.structs.RBush.<ol.SnapSegmentDataType>}
68705 * @private
68706 */
68707 this.rBush_ = new ol.structs.RBush();
68708
68709
68710 /**
68711 * @const
68712 * @private
68713 * @type {Object.<string, function(ol.Feature, ol.geom.Geometry)>}
68714 */
68715 this.SEGMENT_WRITERS_ = {
68716 'Point': this.writePointGeometry_,
68717 'LineString': this.writeLineStringGeometry_,
68718 'LinearRing': this.writeLineStringGeometry_,
68719 'Polygon': this.writePolygonGeometry_,
68720 'MultiPoint': this.writeMultiPointGeometry_,
68721 'MultiLineString': this.writeMultiLineStringGeometry_,
68722 'MultiPolygon': this.writeMultiPolygonGeometry_,
68723 'GeometryCollection': this.writeGeometryCollectionGeometry_,
68724 'Circle': this.writeCircleGeometry_
68725 };
68726};
68727ol.inherits(ol.interaction.Snap, ol.interaction.Pointer);
68728
68729
68730/**
68731 * Add a feature to the collection of features that we may snap to.
68732 * @param {ol.Feature} feature Feature.
68733 * @param {boolean=} opt_listen Whether to listen to the feature change or not
68734 * Defaults to `true`.
68735 * @api
68736 */
68737ol.interaction.Snap.prototype.addFeature = function(feature, opt_listen) {
68738 var listen = opt_listen !== undefined ? opt_listen : true;
68739 var feature_uid = ol.getUid(feature);
68740 var geometry = feature.getGeometry();
68741 if (geometry) {
68742 var segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()];
68743 if (segmentWriter) {
68744 this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(
68745 ol.extent.createEmpty());
68746 segmentWriter.call(this, feature, geometry);
68747 }
68748 }
68749
68750 if (listen) {
68751 this.featureChangeListenerKeys_[feature_uid] = ol.events.listen(
68752 feature,
68753 ol.events.EventType.CHANGE,
68754 this.handleFeatureChange_, this);
68755 }
68756};
68757
68758
68759/**
68760 * @param {ol.Feature} feature Feature.
68761 * @private
68762 */
68763ol.interaction.Snap.prototype.forEachFeatureAdd_ = function(feature) {
68764 this.addFeature(feature);
68765};
68766
68767
68768/**
68769 * @param {ol.Feature} feature Feature.
68770 * @private
68771 */
68772ol.interaction.Snap.prototype.forEachFeatureRemove_ = function(feature) {
68773 this.removeFeature(feature);
68774};
68775
68776
68777/**
68778 * @return {ol.Collection.<ol.Feature>|Array.<ol.Feature>} Features.
68779 * @private
68780 */
68781ol.interaction.Snap.prototype.getFeatures_ = function() {
68782 var features;
68783 if (this.features_) {
68784 features = this.features_;
68785 } else if (this.source_) {
68786 features = this.source_.getFeatures();
68787 }
68788 return /** @type {!Array.<ol.Feature>|!ol.Collection.<ol.Feature>} */ (features);
68789};
68790
68791
68792/**
68793 * @param {ol.source.Vector.Event|ol.Collection.Event} evt Event.
68794 * @private
68795 */
68796ol.interaction.Snap.prototype.handleFeatureAdd_ = function(evt) {
68797 var feature;
68798 if (evt instanceof ol.source.Vector.Event) {
68799 feature = evt.feature;
68800 } else if (evt instanceof ol.Collection.Event) {
68801 feature = evt.element;
68802 }
68803 this.addFeature(/** @type {ol.Feature} */ (feature));
68804};
68805
68806
68807/**
68808 * @param {ol.source.Vector.Event|ol.Collection.Event} evt Event.
68809 * @private
68810 */
68811ol.interaction.Snap.prototype.handleFeatureRemove_ = function(evt) {
68812 var feature;
68813 if (evt instanceof ol.source.Vector.Event) {
68814 feature = evt.feature;
68815 } else if (evt instanceof ol.Collection.Event) {
68816 feature = evt.element;
68817 }
68818 this.removeFeature(/** @type {ol.Feature} */ (feature));
68819};
68820
68821
68822/**
68823 * @param {ol.events.Event} evt Event.
68824 * @private
68825 */
68826ol.interaction.Snap.prototype.handleFeatureChange_ = function(evt) {
68827 var feature = /** @type {ol.Feature} */ (evt.target);
68828 if (this.handlingDownUpSequence) {
68829 var uid = ol.getUid(feature);
68830 if (!(uid in this.pendingFeatures_)) {
68831 this.pendingFeatures_[uid] = feature;
68832 }
68833 } else {
68834 this.updateFeature_(feature);
68835 }
68836};
68837
68838
68839/**
68840 * Remove a feature from the collection of features that we may snap to.
68841 * @param {ol.Feature} feature Feature
68842 * @param {boolean=} opt_unlisten Whether to unlisten to the feature change
68843 * or not. Defaults to `true`.
68844 * @api
68845 */
68846ol.interaction.Snap.prototype.removeFeature = function(feature, opt_unlisten) {
68847 var unlisten = opt_unlisten !== undefined ? opt_unlisten : true;
68848 var feature_uid = ol.getUid(feature);
68849 var extent = this.indexedFeaturesExtents_[feature_uid];
68850 if (extent) {
68851 var rBush = this.rBush_;
68852 var i, nodesToRemove = [];
68853 rBush.forEachInExtent(extent, function(node) {
68854 if (feature === node.feature) {
68855 nodesToRemove.push(node);
68856 }
68857 });
68858 for (i = nodesToRemove.length - 1; i >= 0; --i) {
68859 rBush.remove(nodesToRemove[i]);
68860 }
68861 }
68862
68863 if (unlisten) {
68864 ol.events.unlistenByKey(this.featureChangeListenerKeys_[feature_uid]);
68865 delete this.featureChangeListenerKeys_[feature_uid];
68866 }
68867};
68868
68869
68870/**
68871 * @inheritDoc
68872 */
68873ol.interaction.Snap.prototype.setMap = function(map) {
68874 var currentMap = this.getMap();
68875 var keys = this.featuresListenerKeys_;
68876 var features = this.getFeatures_();
68877
68878 if (currentMap) {
68879 keys.forEach(ol.events.unlistenByKey);
68880 keys.length = 0;
68881 features.forEach(this.forEachFeatureRemove_, this);
68882 }
68883 ol.interaction.Pointer.prototype.setMap.call(this, map);
68884
68885 if (map) {
68886 if (this.features_) {
68887 keys.push(
68888 ol.events.listen(this.features_, ol.CollectionEventType.ADD,
68889 this.handleFeatureAdd_, this),
68890 ol.events.listen(this.features_, ol.CollectionEventType.REMOVE,
68891 this.handleFeatureRemove_, this)
68892 );
68893 } else if (this.source_) {
68894 keys.push(
68895 ol.events.listen(this.source_, ol.source.VectorEventType.ADDFEATURE,
68896 this.handleFeatureAdd_, this),
68897 ol.events.listen(this.source_, ol.source.VectorEventType.REMOVEFEATURE,
68898 this.handleFeatureRemove_, this)
68899 );
68900 }
68901 features.forEach(this.forEachFeatureAdd_, this);
68902 }
68903};
68904
68905
68906/**
68907 * @inheritDoc
68908 */
68909ol.interaction.Snap.prototype.shouldStopEvent = ol.functions.FALSE;
68910
68911
68912/**
68913 * @param {ol.Pixel} pixel Pixel
68914 * @param {ol.Coordinate} pixelCoordinate Coordinate
68915 * @param {ol.Map} map Map.
68916 * @return {ol.SnapResultType} Snap result
68917 */
68918ol.interaction.Snap.prototype.snapTo = function(pixel, pixelCoordinate, map) {
68919
68920 var lowerLeft = map.getCoordinateFromPixel(
68921 [pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
68922 var upperRight = map.getCoordinateFromPixel(
68923 [pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
68924 var box = ol.extent.boundingExtent([lowerLeft, upperRight]);
68925
68926 var segments = this.rBush_.getInExtent(box);
68927
68928 // If snapping on vertices only, don't consider circles
68929 if (this.vertex_ && !this.edge_) {
68930 segments = segments.filter(function(segment) {
68931 return segment.feature.getGeometry().getType() !==
68932 ol.geom.GeometryType.CIRCLE;
68933 });
68934 }
68935
68936 var snappedToVertex = false;
68937 var snapped = false;
68938 var vertex = null;
68939 var vertexPixel = null;
68940 var dist, pixel1, pixel2, squaredDist1, squaredDist2;
68941 if (segments.length > 0) {
68942 this.pixelCoordinate_ = pixelCoordinate;
68943 segments.sort(this.sortByDistance_);
68944 var closestSegment = segments[0].segment;
68945 var isCircle = segments[0].feature.getGeometry().getType() ===
68946 ol.geom.GeometryType.CIRCLE;
68947 if (this.vertex_ && !this.edge_) {
68948 pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
68949 pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
68950 squaredDist1 = ol.coordinate.squaredDistance(pixel, pixel1);
68951 squaredDist2 = ol.coordinate.squaredDistance(pixel, pixel2);
68952 dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
68953 snappedToVertex = dist <= this.pixelTolerance_;
68954 if (snappedToVertex) {
68955 snapped = true;
68956 vertex = squaredDist1 > squaredDist2 ?
68957 closestSegment[1] : closestSegment[0];
68958 vertexPixel = map.getPixelFromCoordinate(vertex);
68959 }
68960 } else if (this.edge_) {
68961 if (isCircle) {
68962 vertex = ol.coordinate.closestOnCircle(pixelCoordinate,
68963 /** @type {ol.geom.Circle} */ (segments[0].feature.getGeometry()));
68964 } else {
68965 vertex = (ol.coordinate.closestOnSegment(pixelCoordinate,
68966 closestSegment));
68967 }
68968 vertexPixel = map.getPixelFromCoordinate(vertex);
68969 if (ol.coordinate.distance(pixel, vertexPixel) <= this.pixelTolerance_) {
68970 snapped = true;
68971 if (this.vertex_ && !isCircle) {
68972 pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
68973 pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
68974 squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
68975 squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
68976 dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
68977 snappedToVertex = dist <= this.pixelTolerance_;
68978 if (snappedToVertex) {
68979 vertex = squaredDist1 > squaredDist2 ?
68980 closestSegment[1] : closestSegment[0];
68981 vertexPixel = map.getPixelFromCoordinate(vertex);
68982 }
68983 }
68984 }
68985 }
68986 if (snapped) {
68987 vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
68988 }
68989 }
68990 return /** @type {ol.SnapResultType} */ ({
68991 snapped: snapped,
68992 vertex: vertex,
68993 vertexPixel: vertexPixel
68994 });
68995};
68996
68997
68998/**
68999 * @param {ol.Feature} feature Feature
69000 * @private
69001 */
69002ol.interaction.Snap.prototype.updateFeature_ = function(feature) {
69003 this.removeFeature(feature, false);
69004 this.addFeature(feature, false);
69005};
69006
69007
69008/**
69009 * @param {ol.Feature} feature Feature
69010 * @param {ol.geom.Circle} geometry Geometry.
69011 * @private
69012 */
69013ol.interaction.Snap.prototype.writeCircleGeometry_ = function(feature, geometry) {
69014 var polygon = ol.geom.Polygon.fromCircle(geometry);
69015 var coordinates = polygon.getCoordinates()[0];
69016 var i, ii, segment, segmentData;
69017 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
69018 segment = coordinates.slice(i, i + 2);
69019 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69020 feature: feature,
69021 segment: segment
69022 });
69023 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
69024 }
69025};
69026
69027
69028/**
69029 * @param {ol.Feature} feature Feature
69030 * @param {ol.geom.GeometryCollection} geometry Geometry.
69031 * @private
69032 */
69033ol.interaction.Snap.prototype.writeGeometryCollectionGeometry_ = function(feature, geometry) {
69034 var i, geometries = geometry.getGeometriesArray();
69035 for (i = 0; i < geometries.length; ++i) {
69036 var segmentWriter = this.SEGMENT_WRITERS_[geometries[i].getType()];
69037 if (segmentWriter) {
69038 segmentWriter.call(this, feature, geometries[i]);
69039 }
69040 }
69041};
69042
69043
69044/**
69045 * @param {ol.Feature} feature Feature
69046 * @param {ol.geom.LineString} geometry Geometry.
69047 * @private
69048 */
69049ol.interaction.Snap.prototype.writeLineStringGeometry_ = function(feature, geometry) {
69050 var coordinates = geometry.getCoordinates();
69051 var i, ii, segment, segmentData;
69052 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
69053 segment = coordinates.slice(i, i + 2);
69054 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69055 feature: feature,
69056 segment: segment
69057 });
69058 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
69059 }
69060};
69061
69062
69063/**
69064 * @param {ol.Feature} feature Feature
69065 * @param {ol.geom.MultiLineString} geometry Geometry.
69066 * @private
69067 */
69068ol.interaction.Snap.prototype.writeMultiLineStringGeometry_ = function(feature, geometry) {
69069 var lines = geometry.getCoordinates();
69070 var coordinates, i, ii, j, jj, segment, segmentData;
69071 for (j = 0, jj = lines.length; j < jj; ++j) {
69072 coordinates = lines[j];
69073 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
69074 segment = coordinates.slice(i, i + 2);
69075 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69076 feature: feature,
69077 segment: segment
69078 });
69079 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
69080 }
69081 }
69082};
69083
69084
69085/**
69086 * @param {ol.Feature} feature Feature
69087 * @param {ol.geom.MultiPoint} geometry Geometry.
69088 * @private
69089 */
69090ol.interaction.Snap.prototype.writeMultiPointGeometry_ = function(feature, geometry) {
69091 var points = geometry.getCoordinates();
69092 var coordinates, i, ii, segmentData;
69093 for (i = 0, ii = points.length; i < ii; ++i) {
69094 coordinates = points[i];
69095 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69096 feature: feature,
69097 segment: [coordinates, coordinates]
69098 });
69099 this.rBush_.insert(geometry.getExtent(), segmentData);
69100 }
69101};
69102
69103
69104/**
69105 * @param {ol.Feature} feature Feature
69106 * @param {ol.geom.MultiPolygon} geometry Geometry.
69107 * @private
69108 */
69109ol.interaction.Snap.prototype.writeMultiPolygonGeometry_ = function(feature, geometry) {
69110 var polygons = geometry.getCoordinates();
69111 var coordinates, i, ii, j, jj, k, kk, rings, segment, segmentData;
69112 for (k = 0, kk = polygons.length; k < kk; ++k) {
69113 rings = polygons[k];
69114 for (j = 0, jj = rings.length; j < jj; ++j) {
69115 coordinates = rings[j];
69116 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
69117 segment = coordinates.slice(i, i + 2);
69118 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69119 feature: feature,
69120 segment: segment
69121 });
69122 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
69123 }
69124 }
69125 }
69126};
69127
69128
69129/**
69130 * @param {ol.Feature} feature Feature
69131 * @param {ol.geom.Point} geometry Geometry.
69132 * @private
69133 */
69134ol.interaction.Snap.prototype.writePointGeometry_ = function(feature, geometry) {
69135 var coordinates = geometry.getCoordinates();
69136 var segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69137 feature: feature,
69138 segment: [coordinates, coordinates]
69139 });
69140 this.rBush_.insert(geometry.getExtent(), segmentData);
69141};
69142
69143
69144/**
69145 * @param {ol.Feature} feature Feature
69146 * @param {ol.geom.Polygon} geometry Geometry.
69147 * @private
69148 */
69149ol.interaction.Snap.prototype.writePolygonGeometry_ = function(feature, geometry) {
69150 var rings = geometry.getCoordinates();
69151 var coordinates, i, ii, j, jj, segment, segmentData;
69152 for (j = 0, jj = rings.length; j < jj; ++j) {
69153 coordinates = rings[j];
69154 for (i = 0, ii = coordinates.length - 1; i < ii; ++i) {
69155 segment = coordinates.slice(i, i + 2);
69156 segmentData = /** @type {ol.SnapSegmentDataType} */ ({
69157 feature: feature,
69158 segment: segment
69159 });
69160 this.rBush_.insert(ol.extent.boundingExtent(segment), segmentData);
69161 }
69162 }
69163};
69164
69165
69166/**
69167 * Handle all pointer events events.
69168 * @param {ol.MapBrowserEvent} evt A move event.
69169 * @return {boolean} Pass the event to other interactions.
69170 * @this {ol.interaction.Snap}
69171 * @private
69172 */
69173ol.interaction.Snap.handleEvent_ = function(evt) {
69174 var result = this.snapTo(evt.pixel, evt.coordinate, evt.map);
69175 if (result.snapped) {
69176 evt.coordinate = result.vertex.slice(0, 2);
69177 evt.pixel = result.vertexPixel;
69178 }
69179 return ol.interaction.Pointer.handleEvent.call(this, evt);
69180};
69181
69182
69183/**
69184 * @param {ol.MapBrowserPointerEvent} evt Event.
69185 * @return {boolean} Stop drag sequence?
69186 * @this {ol.interaction.Snap}
69187 * @private
69188 */
69189ol.interaction.Snap.handleUpEvent_ = function(evt) {
69190 var featuresToUpdate = ol.obj.getValues(this.pendingFeatures_);
69191 if (featuresToUpdate.length) {
69192 featuresToUpdate.forEach(this.updateFeature_, this);
69193 this.pendingFeatures_ = {};
69194 }
69195 return false;
69196};
69197
69198
69199/**
69200 * Sort segments by distance, helper function
69201 * @param {ol.SnapSegmentDataType} a The first segment data.
69202 * @param {ol.SnapSegmentDataType} b The second segment data.
69203 * @return {number} The difference in distance.
69204 * @this {ol.interaction.Snap}
69205 */
69206ol.interaction.Snap.sortByDistance = function(a, b) {
69207 return ol.coordinate.squaredDistanceToSegment(
69208 this.pixelCoordinate_, a.segment) -
69209 ol.coordinate.squaredDistanceToSegment(
69210 this.pixelCoordinate_, b.segment);
69211};
69212
69213goog.provide('ol.interaction.TranslateEventType');
69214
69215
69216/**
69217 * @enum {string}
69218 */
69219ol.interaction.TranslateEventType = {
69220 /**
69221 * Triggered upon feature translation start.
69222 * @event ol.interaction.Translate.Event#translatestart
69223 * @api
69224 */
69225 TRANSLATESTART: 'translatestart',
69226 /**
69227 * Triggered upon feature translation.
69228 * @event ol.interaction.Translate.Event#translating
69229 * @api
69230 */
69231 TRANSLATING: 'translating',
69232 /**
69233 * Triggered upon feature translation end.
69234 * @event ol.interaction.Translate.Event#translateend
69235 * @api
69236 */
69237 TRANSLATEEND: 'translateend'
69238};
69239
69240goog.provide('ol.interaction.Translate');
69241
69242goog.require('ol');
69243goog.require('ol.Collection');
69244goog.require('ol.Object');
69245goog.require('ol.events');
69246goog.require('ol.events.Event');
69247goog.require('ol.functions');
69248goog.require('ol.array');
69249goog.require('ol.interaction.Pointer');
69250goog.require('ol.interaction.Property');
69251goog.require('ol.interaction.TranslateEventType');
69252
69253
69254/**
69255 * @classdesc
69256 * Interaction for translating (moving) features.
69257 *
69258 * @constructor
69259 * @extends {ol.interaction.Pointer}
69260 * @fires ol.interaction.Translate.Event
69261 * @param {olx.interaction.TranslateOptions=} opt_options Options.
69262 * @api
69263 */
69264ol.interaction.Translate = function(opt_options) {
69265 ol.interaction.Pointer.call(this, {
69266 handleDownEvent: ol.interaction.Translate.handleDownEvent_,
69267 handleDragEvent: ol.interaction.Translate.handleDragEvent_,
69268 handleMoveEvent: ol.interaction.Translate.handleMoveEvent_,
69269 handleUpEvent: ol.interaction.Translate.handleUpEvent_
69270 });
69271
69272 var options = opt_options ? opt_options : {};
69273
69274 /**
69275 * The last position we translated to.
69276 * @type {ol.Coordinate}
69277 * @private
69278 */
69279 this.lastCoordinate_ = null;
69280
69281
69282 /**
69283 * @type {ol.Collection.<ol.Feature>}
69284 * @private
69285 */
69286 this.features_ = options.features !== undefined ? options.features : null;
69287
69288 /** @type {function(ol.layer.Layer): boolean} */
69289 var layerFilter;
69290 if (options.layers) {
69291 if (typeof options.layers === 'function') {
69292 layerFilter = options.layers;
69293 } else {
69294 var layers = options.layers;
69295 layerFilter = function(layer) {
69296 return ol.array.includes(layers, layer);
69297 };
69298 }
69299 } else {
69300 layerFilter = ol.functions.TRUE;
69301 }
69302
69303 /**
69304 * @private
69305 * @type {function(ol.layer.Layer): boolean}
69306 */
69307 this.layerFilter_ = layerFilter;
69308
69309 /**
69310 * @private
69311 * @type {number}
69312 */
69313 this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;
69314
69315 /**
69316 * @type {ol.Feature}
69317 * @private
69318 */
69319 this.lastFeature_ = null;
69320
69321 ol.events.listen(this,
69322 ol.Object.getChangeEventType(ol.interaction.Property.ACTIVE),
69323 this.handleActiveChanged_, this);
69324
69325};
69326ol.inherits(ol.interaction.Translate, ol.interaction.Pointer);
69327
69328
69329/**
69330 * @param {ol.MapBrowserPointerEvent} event Event.
69331 * @return {boolean} Start drag sequence?
69332 * @this {ol.interaction.Translate}
69333 * @private
69334 */
69335ol.interaction.Translate.handleDownEvent_ = function(event) {
69336 this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
69337 if (!this.lastCoordinate_ && this.lastFeature_) {
69338 this.lastCoordinate_ = event.coordinate;
69339 ol.interaction.Translate.handleMoveEvent_.call(this, event);
69340
69341 var features = this.features_ || new ol.Collection([this.lastFeature_]);
69342
69343 this.dispatchEvent(
69344 new ol.interaction.Translate.Event(
69345 ol.interaction.TranslateEventType.TRANSLATESTART, features,
69346 event.coordinate));
69347 return true;
69348 }
69349 return false;
69350};
69351
69352
69353/**
69354 * @param {ol.MapBrowserPointerEvent} event Event.
69355 * @return {boolean} Stop drag sequence?
69356 * @this {ol.interaction.Translate}
69357 * @private
69358 */
69359ol.interaction.Translate.handleUpEvent_ = function(event) {
69360 if (this.lastCoordinate_) {
69361 this.lastCoordinate_ = null;
69362 ol.interaction.Translate.handleMoveEvent_.call(this, event);
69363
69364 var features = this.features_ || new ol.Collection([this.lastFeature_]);
69365
69366 this.dispatchEvent(
69367 new ol.interaction.Translate.Event(
69368 ol.interaction.TranslateEventType.TRANSLATEEND, features,
69369 event.coordinate));
69370 return true;
69371 }
69372 return false;
69373};
69374
69375
69376/**
69377 * @param {ol.MapBrowserPointerEvent} event Event.
69378 * @this {ol.interaction.Translate}
69379 * @private
69380 */
69381ol.interaction.Translate.handleDragEvent_ = function(event) {
69382 if (this.lastCoordinate_) {
69383 var newCoordinate = event.coordinate;
69384 var deltaX = newCoordinate[0] - this.lastCoordinate_[0];
69385 var deltaY = newCoordinate[1] - this.lastCoordinate_[1];
69386
69387 var features = this.features_ || new ol.Collection([this.lastFeature_]);
69388
69389 features.forEach(function(feature) {
69390 var geom = feature.getGeometry();
69391 geom.translate(deltaX, deltaY);
69392 feature.setGeometry(geom);
69393 });
69394
69395 this.lastCoordinate_ = newCoordinate;
69396 this.dispatchEvent(
69397 new ol.interaction.Translate.Event(
69398 ol.interaction.TranslateEventType.TRANSLATING, features,
69399 newCoordinate));
69400 }
69401};
69402
69403
69404/**
69405 * @param {ol.MapBrowserEvent} event Event.
69406 * @this {ol.interaction.Translate}
69407 * @private
69408 */
69409ol.interaction.Translate.handleMoveEvent_ = function(event) {
69410 var elem = event.map.getViewport();
69411
69412 // Change the cursor to grab/grabbing if hovering any of the features managed
69413 // by the interaction
69414 if (this.featuresAtPixel_(event.pixel, event.map)) {
69415 elem.classList.remove(this.lastCoordinate_ ? 'ol-grab' : 'ol-grabbing');
69416 elem.classList.add(this.lastCoordinate_ ? 'ol-grabbing' : 'ol-grab');
69417 } else {
69418 elem.classList.remove('ol-grab', 'ol-grabbing');
69419 }
69420};
69421
69422
69423/**
69424 * Tests to see if the given coordinates intersects any of our selected
69425 * features.
69426 * @param {ol.Pixel} pixel Pixel coordinate to test for intersection.
69427 * @param {ol.Map} map Map to test the intersection on.
69428 * @return {ol.Feature} Returns the feature found at the specified pixel
69429 * coordinates.
69430 * @private
69431 */
69432ol.interaction.Translate.prototype.featuresAtPixel_ = function(pixel, map) {
69433 return map.forEachFeatureAtPixel(pixel,
69434 function(feature) {
69435 if (!this.features_ ||
69436 ol.array.includes(this.features_.getArray(), feature)) {
69437 return feature;
69438 }
69439 }.bind(this), {
69440 layerFilter: this.layerFilter_,
69441 hitTolerance: this.hitTolerance_
69442 });
69443};
69444
69445
69446/**
69447 * Returns the Hit-detection tolerance.
69448 * @returns {number} Hit tolerance in pixels.
69449 * @api
69450 */
69451ol.interaction.Translate.prototype.getHitTolerance = function() {
69452 return this.hitTolerance_;
69453};
69454
69455
69456/**
69457 * Hit-detection tolerance. Pixels inside the radius around the given position
69458 * will be checked for features. This only works for the canvas renderer and
69459 * not for WebGL.
69460 * @param {number} hitTolerance Hit tolerance in pixels.
69461 * @api
69462 */
69463ol.interaction.Translate.prototype.setHitTolerance = function(hitTolerance) {
69464 this.hitTolerance_ = hitTolerance;
69465};
69466
69467
69468/**
69469 * @inheritDoc
69470 */
69471ol.interaction.Translate.prototype.setMap = function(map) {
69472 var oldMap = this.getMap();
69473 ol.interaction.Pointer.prototype.setMap.call(this, map);
69474 this.updateState_(oldMap);
69475};
69476
69477
69478/**
69479 * @private
69480 */
69481ol.interaction.Translate.prototype.handleActiveChanged_ = function() {
69482 this.updateState_(null);
69483};
69484
69485
69486/**
69487 * @param {ol.Map} oldMap Old map.
69488 * @private
69489 */
69490ol.interaction.Translate.prototype.updateState_ = function(oldMap) {
69491 var map = this.getMap();
69492 var active = this.getActive();
69493 if (!map || !active) {
69494 map = map || oldMap;
69495 if (map) {
69496 var elem = map.getViewport();
69497 elem.classList.remove('ol-grab', 'ol-grabbing');
69498 }
69499 }
69500};
69501
69502
69503/**
69504 * @classdesc
69505 * Events emitted by {@link ol.interaction.Translate} instances are instances of
69506 * this type.
69507 *
69508 * @constructor
69509 * @extends {ol.events.Event}
69510 * @implements {oli.interaction.TranslateEvent}
69511 * @param {ol.interaction.TranslateEventType} type Type.
69512 * @param {ol.Collection.<ol.Feature>} features The features translated.
69513 * @param {ol.Coordinate} coordinate The event coordinate.
69514 */
69515ol.interaction.Translate.Event = function(type, features, coordinate) {
69516
69517 ol.events.Event.call(this, type);
69518
69519 /**
69520 * The features being translated.
69521 * @type {ol.Collection.<ol.Feature>}
69522 * @api
69523 */
69524 this.features = features;
69525
69526 /**
69527 * The coordinate of the drag event.
69528 * @const
69529 * @type {ol.Coordinate}
69530 * @api
69531 */
69532 this.coordinate = coordinate;
69533};
69534ol.inherits(ol.interaction.Translate.Event, ol.events.Event);
69535
69536goog.provide('ol.layer.Heatmap');
69537
69538goog.require('ol.events');
69539goog.require('ol');
69540goog.require('ol.Object');
69541goog.require('ol.dom');
69542goog.require('ol.layer.Vector');
69543goog.require('ol.math');
69544goog.require('ol.obj');
69545goog.require('ol.render.EventType');
69546goog.require('ol.style.Icon');
69547goog.require('ol.style.Style');
69548
69549
69550/**
69551 * @classdesc
69552 * Layer for rendering vector data as a heatmap.
69553 * Note that any property set in the options is set as a {@link ol.Object}
69554 * property on the layer object; for example, setting `title: 'My Title'` in the
69555 * options means that `title` is observable, and has get/set accessors.
69556 *
69557 * @constructor
69558 * @extends {ol.layer.Vector}
69559 * @fires ol.render.Event
69560 * @param {olx.layer.HeatmapOptions=} opt_options Options.
69561 * @api
69562 */
69563ol.layer.Heatmap = function(opt_options) {
69564 var options = opt_options ? opt_options : {};
69565
69566 var baseOptions = ol.obj.assign({}, options);
69567
69568 delete baseOptions.gradient;
69569 delete baseOptions.radius;
69570 delete baseOptions.blur;
69571 delete baseOptions.shadow;
69572 delete baseOptions.weight;
69573 ol.layer.Vector.call(this, /** @type {olx.layer.VectorOptions} */ (baseOptions));
69574
69575 /**
69576 * @private
69577 * @type {Uint8ClampedArray}
69578 */
69579 this.gradient_ = null;
69580
69581 /**
69582 * @private
69583 * @type {number}
69584 */
69585 this.shadow_ = options.shadow !== undefined ? options.shadow : 250;
69586
69587 /**
69588 * @private
69589 * @type {string|undefined}
69590 */
69591 this.circleImage_ = undefined;
69592
69593 /**
69594 * @private
69595 * @type {Array.<Array.<ol.style.Style>>}
69596 */
69597 this.styleCache_ = null;
69598
69599 ol.events.listen(this,
69600 ol.Object.getChangeEventType(ol.layer.Heatmap.Property_.GRADIENT),
69601 this.handleGradientChanged_, this);
69602
69603 this.setGradient(options.gradient ?
69604 options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);
69605
69606 this.setBlur(options.blur !== undefined ? options.blur : 15);
69607
69608 this.setRadius(options.radius !== undefined ? options.radius : 8);
69609
69610 ol.events.listen(this,
69611 ol.Object.getChangeEventType(ol.layer.Heatmap.Property_.BLUR),
69612 this.handleStyleChanged_, this);
69613 ol.events.listen(this,
69614 ol.Object.getChangeEventType(ol.layer.Heatmap.Property_.RADIUS),
69615 this.handleStyleChanged_, this);
69616
69617 this.handleStyleChanged_();
69618
69619 var weight = options.weight ? options.weight : 'weight';
69620 var weightFunction;
69621 if (typeof weight === 'string') {
69622 weightFunction = function(feature) {
69623 return feature.get(weight);
69624 };
69625 } else {
69626 weightFunction = weight;
69627 }
69628
69629 this.setStyle(function(feature, resolution) {
69630 var weight = weightFunction(feature);
69631 var opacity = weight !== undefined ? ol.math.clamp(weight, 0, 1) : 1;
69632 // cast to 8 bits
69633 var index = (255 * opacity) | 0;
69634 var style = this.styleCache_[index];
69635 if (!style) {
69636 style = [
69637 new ol.style.Style({
69638 image: new ol.style.Icon({
69639 opacity: opacity,
69640 src: this.circleImage_
69641 })
69642 })
69643 ];
69644 this.styleCache_[index] = style;
69645 }
69646 return style;
69647 }.bind(this));
69648
69649 // For performance reasons, don't sort the features before rendering.
69650 // The render order is not relevant for a heatmap representation.
69651 this.setRenderOrder(null);
69652
69653 ol.events.listen(this, ol.render.EventType.RENDER, this.handleRender_, this);
69654};
69655ol.inherits(ol.layer.Heatmap, ol.layer.Vector);
69656
69657
69658/**
69659 * @const
69660 * @type {Array.<string>}
69661 */
69662ol.layer.Heatmap.DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];
69663
69664
69665/**
69666 * @param {Array.<string>} colors A list of colored.
69667 * @return {Uint8ClampedArray} An array.
69668 * @private
69669 */
69670ol.layer.Heatmap.createGradient_ = function(colors) {
69671 var width = 1;
69672 var height = 256;
69673 var context = ol.dom.createCanvasContext2D(width, height);
69674
69675 var gradient = context.createLinearGradient(0, 0, width, height);
69676 var step = 1 / (colors.length - 1);
69677 for (var i = 0, ii = colors.length; i < ii; ++i) {
69678 gradient.addColorStop(i * step, colors[i]);
69679 }
69680
69681 context.fillStyle = gradient;
69682 context.fillRect(0, 0, width, height);
69683
69684 return context.getImageData(0, 0, width, height).data;
69685};
69686
69687
69688/**
69689 * @return {string} Data URL for a circle.
69690 * @private
69691 */
69692ol.layer.Heatmap.prototype.createCircle_ = function() {
69693 var radius = this.getRadius();
69694 var blur = this.getBlur();
69695 var halfSize = radius + blur + 1;
69696 var size = 2 * halfSize;
69697 var context = ol.dom.createCanvasContext2D(size, size);
69698 context.shadowOffsetX = context.shadowOffsetY = this.shadow_;
69699 context.shadowBlur = blur;
69700 context.shadowColor = '#000';
69701 context.beginPath();
69702 var center = halfSize - this.shadow_;
69703 context.arc(center, center, radius, 0, Math.PI * 2, true);
69704 context.fill();
69705 return context.canvas.toDataURL();
69706};
69707
69708
69709/**
69710 * Return the blur size in pixels.
69711 * @return {number} Blur size in pixels.
69712 * @api
69713 * @observable
69714 */
69715ol.layer.Heatmap.prototype.getBlur = function() {
69716 return /** @type {number} */ (this.get(ol.layer.Heatmap.Property_.BLUR));
69717};
69718
69719
69720/**
69721 * Return the gradient colors as array of strings.
69722 * @return {Array.<string>} Colors.
69723 * @api
69724 * @observable
69725 */
69726ol.layer.Heatmap.prototype.getGradient = function() {
69727 return /** @type {Array.<string>} */ (
69728 this.get(ol.layer.Heatmap.Property_.GRADIENT));
69729};
69730
69731
69732/**
69733 * Return the size of the radius in pixels.
69734 * @return {number} Radius size in pixel.
69735 * @api
69736 * @observable
69737 */
69738ol.layer.Heatmap.prototype.getRadius = function() {
69739 return /** @type {number} */ (this.get(ol.layer.Heatmap.Property_.RADIUS));
69740};
69741
69742
69743/**
69744 * @private
69745 */
69746ol.layer.Heatmap.prototype.handleGradientChanged_ = function() {
69747 this.gradient_ = ol.layer.Heatmap.createGradient_(this.getGradient());
69748};
69749
69750
69751/**
69752 * @private
69753 */
69754ol.layer.Heatmap.prototype.handleStyleChanged_ = function() {
69755 this.circleImage_ = this.createCircle_();
69756 this.styleCache_ = new Array(256);
69757 this.changed();
69758};
69759
69760
69761/**
69762 * @param {ol.render.Event} event Post compose event
69763 * @private
69764 */
69765ol.layer.Heatmap.prototype.handleRender_ = function(event) {
69766 var context = event.context;
69767 var canvas = context.canvas;
69768 var image = context.getImageData(0, 0, canvas.width, canvas.height);
69769 var view8 = image.data;
69770 var i, ii, alpha;
69771 for (i = 0, ii = view8.length; i < ii; i += 4) {
69772 alpha = view8[i + 3] * 4;
69773 if (alpha) {
69774 view8[i] = this.gradient_[alpha];
69775 view8[i + 1] = this.gradient_[alpha + 1];
69776 view8[i + 2] = this.gradient_[alpha + 2];
69777 }
69778 }
69779 context.putImageData(image, 0, 0);
69780};
69781
69782
69783/**
69784 * Set the blur size in pixels.
69785 * @param {number} blur Blur size in pixels.
69786 * @api
69787 * @observable
69788 */
69789ol.layer.Heatmap.prototype.setBlur = function(blur) {
69790 this.set(ol.layer.Heatmap.Property_.BLUR, blur);
69791};
69792
69793
69794/**
69795 * Set the gradient colors as array of strings.
69796 * @param {Array.<string>} colors Gradient.
69797 * @api
69798 * @observable
69799 */
69800ol.layer.Heatmap.prototype.setGradient = function(colors) {
69801 this.set(ol.layer.Heatmap.Property_.GRADIENT, colors);
69802};
69803
69804
69805/**
69806 * Set the size of the radius in pixels.
69807 * @param {number} radius Radius size in pixel.
69808 * @api
69809 * @observable
69810 */
69811ol.layer.Heatmap.prototype.setRadius = function(radius) {
69812 this.set(ol.layer.Heatmap.Property_.RADIUS, radius);
69813};
69814
69815
69816/**
69817 * @enum {string}
69818 * @private
69819 */
69820ol.layer.Heatmap.Property_ = {
69821 BLUR: 'blur',
69822 GRADIENT: 'gradient',
69823 RADIUS: 'radius'
69824};
69825
69826goog.provide('ol.renderer.canvas.IntermediateCanvas');
69827
69828goog.require('ol');
69829goog.require('ol.coordinate');
69830goog.require('ol.dom');
69831goog.require('ol.extent');
69832goog.require('ol.renderer.canvas.Layer');
69833goog.require('ol.transform');
69834
69835
69836/**
69837 * @constructor
69838 * @abstract
69839 * @extends {ol.renderer.canvas.Layer}
69840 * @param {ol.layer.Layer} layer Layer.
69841 */
69842ol.renderer.canvas.IntermediateCanvas = function(layer) {
69843
69844 ol.renderer.canvas.Layer.call(this, layer);
69845
69846 /**
69847 * @protected
69848 * @type {ol.Transform}
69849 */
69850 this.coordinateToCanvasPixelTransform = ol.transform.create();
69851
69852 /**
69853 * @private
69854 * @type {CanvasRenderingContext2D}
69855 */
69856 this.hitCanvasContext_ = null;
69857
69858};
69859ol.inherits(ol.renderer.canvas.IntermediateCanvas, ol.renderer.canvas.Layer);
69860
69861
69862/**
69863 * @inheritDoc
69864 */
69865ol.renderer.canvas.IntermediateCanvas.prototype.composeFrame = function(frameState, layerState, context) {
69866
69867 this.preCompose(context, frameState);
69868
69869 var image = this.getImage();
69870 if (image) {
69871
69872 // clipped rendering if layer extent is set
69873 var extent = layerState.extent;
69874 var clipped = extent !== undefined &&
69875 !ol.extent.containsExtent(extent, frameState.extent) &&
69876 ol.extent.intersects(extent, frameState.extent);
69877 if (clipped) {
69878 this.clip(context, frameState, /** @type {ol.Extent} */ (extent));
69879 }
69880
69881 var imageTransform = this.getImageTransform();
69882 // for performance reasons, context.save / context.restore is not used
69883 // to save and restore the transformation matrix and the opacity.
69884 // see http://jsperf.com/context-save-restore-versus-variable
69885 var alpha = context.globalAlpha;
69886 context.globalAlpha = layerState.opacity;
69887
69888 // for performance reasons, context.setTransform is only used
69889 // when the view is rotated. see http://jsperf.com/canvas-transform
69890 var dx = imageTransform[4];
69891 var dy = imageTransform[5];
69892 var dw = image.width * imageTransform[0];
69893 var dh = image.height * imageTransform[3];
69894 context.drawImage(image, 0, 0, +image.width, +image.height,
69895 Math.round(dx), Math.round(dy), Math.round(dw), Math.round(dh));
69896 context.globalAlpha = alpha;
69897
69898 if (clipped) {
69899 context.restore();
69900 }
69901 }
69902
69903 this.postCompose(context, frameState, layerState);
69904};
69905
69906
69907/**
69908 * @abstract
69909 * @return {HTMLCanvasElement|HTMLVideoElement|Image} Canvas.
69910 */
69911ol.renderer.canvas.IntermediateCanvas.prototype.getImage = function() {};
69912
69913
69914/**
69915 * @abstract
69916 * @return {!ol.Transform} Image transform.
69917 */
69918ol.renderer.canvas.IntermediateCanvas.prototype.getImageTransform = function() {};
69919
69920
69921/**
69922 * @inheritDoc
69923 */
69924ol.renderer.canvas.IntermediateCanvas.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {
69925 var layer = this.getLayer();
69926 var source = layer.getSource();
69927 var resolution = frameState.viewState.resolution;
69928 var rotation = frameState.viewState.rotation;
69929 var skippedFeatureUids = frameState.skippedFeatureUids;
69930 return source.forEachFeatureAtCoordinate(
69931 coordinate, resolution, rotation, hitTolerance, skippedFeatureUids,
69932 /**
69933 * @param {ol.Feature|ol.render.Feature} feature Feature.
69934 * @return {?} Callback result.
69935 */
69936 function(feature) {
69937 return callback.call(thisArg, feature, layer);
69938 });
69939};
69940
69941
69942/**
69943 * @inheritDoc
69944 */
69945ol.renderer.canvas.IntermediateCanvas.prototype.forEachLayerAtCoordinate = function(coordinate, frameState, callback, thisArg) {
69946 if (!this.getImage()) {
69947 return undefined;
69948 }
69949
69950 if (this.getLayer().getSource().forEachFeatureAtCoordinate !== ol.nullFunction) {
69951 // for ImageVector sources use the original hit-detection logic,
69952 // so that for example also transparent polygons are detected
69953 return ol.renderer.canvas.Layer.prototype.forEachLayerAtCoordinate.apply(this, arguments);
69954 } else {
69955 var pixel = ol.transform.apply(this.coordinateToCanvasPixelTransform, coordinate.slice());
69956 ol.coordinate.scale(pixel, frameState.viewState.resolution / this.renderedResolution);
69957
69958 if (!this.hitCanvasContext_) {
69959 this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
69960 }
69961
69962 this.hitCanvasContext_.clearRect(0, 0, 1, 1);
69963 this.hitCanvasContext_.drawImage(this.getImage(), pixel[0], pixel[1], 1, 1, 0, 0, 1, 1);
69964
69965 var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;
69966 if (imageData[3] > 0) {
69967 return callback.call(thisArg, this.getLayer(), imageData);
69968 } else {
69969 return undefined;
69970 }
69971 }
69972};
69973
69974goog.provide('ol.renderer.canvas.ImageLayer');
69975
69976goog.require('ol');
69977goog.require('ol.ViewHint');
69978goog.require('ol.extent');
69979goog.require('ol.renderer.canvas.IntermediateCanvas');
69980goog.require('ol.transform');
69981
69982
69983/**
69984 * @constructor
69985 * @extends {ol.renderer.canvas.IntermediateCanvas}
69986 * @param {ol.layer.Image} imageLayer Single image layer.
69987 */
69988ol.renderer.canvas.ImageLayer = function(imageLayer) {
69989
69990 ol.renderer.canvas.IntermediateCanvas.call(this, imageLayer);
69991
69992 /**
69993 * @private
69994 * @type {?ol.ImageBase}
69995 */
69996 this.image_ = null;
69997
69998 /**
69999 * @private
70000 * @type {ol.Transform}
70001 */
70002 this.imageTransform_ = ol.transform.create();
70003
70004};
70005ol.inherits(ol.renderer.canvas.ImageLayer, ol.renderer.canvas.IntermediateCanvas);
70006
70007
70008/**
70009 * @inheritDoc
70010 */
70011ol.renderer.canvas.ImageLayer.prototype.getImage = function() {
70012 return !this.image_ ? null : this.image_.getImage();
70013};
70014
70015
70016/**
70017 * @inheritDoc
70018 */
70019ol.renderer.canvas.ImageLayer.prototype.getImageTransform = function() {
70020 return this.imageTransform_;
70021};
70022
70023
70024/**
70025 * @inheritDoc
70026 */
70027ol.renderer.canvas.ImageLayer.prototype.prepareFrame = function(frameState, layerState) {
70028
70029 var pixelRatio = frameState.pixelRatio;
70030 var size = frameState.size;
70031 var viewState = frameState.viewState;
70032 var viewCenter = viewState.center;
70033 var viewResolution = viewState.resolution;
70034
70035 var image;
70036 var imageLayer = /** @type {ol.layer.Image} */ (this.getLayer());
70037 var imageSource = imageLayer.getSource();
70038
70039 var hints = frameState.viewHints;
70040
70041 var renderedExtent = frameState.extent;
70042 if (layerState.extent !== undefined) {
70043 renderedExtent = ol.extent.getIntersection(
70044 renderedExtent, layerState.extent);
70045 }
70046
70047 if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] &&
70048 !ol.extent.isEmpty(renderedExtent)) {
70049 var projection = viewState.projection;
70050 if (!ol.ENABLE_RASTER_REPROJECTION) {
70051 var sourceProjection = imageSource.getProjection();
70052 if (sourceProjection) {
70053 projection = sourceProjection;
70054 }
70055 }
70056 image = imageSource.getImage(
70057 renderedExtent, viewResolution, pixelRatio, projection);
70058 if (image) {
70059 var loaded = this.loadImage(image);
70060 if (loaded) {
70061 this.image_ = image;
70062 }
70063 }
70064 }
70065
70066 if (this.image_) {
70067 image = this.image_;
70068 var imageExtent = image.getExtent();
70069 var imageResolution = image.getResolution();
70070 var imagePixelRatio = image.getPixelRatio();
70071 var scale = pixelRatio * imageResolution /
70072 (viewResolution * imagePixelRatio);
70073 var transform = ol.transform.compose(this.imageTransform_,
70074 pixelRatio * size[0] / 2, pixelRatio * size[1] / 2,
70075 scale, scale,
70076 0,
70077 imagePixelRatio * (imageExtent[0] - viewCenter[0]) / imageResolution,
70078 imagePixelRatio * (viewCenter[1] - imageExtent[3]) / imageResolution);
70079 ol.transform.compose(this.coordinateToCanvasPixelTransform,
70080 pixelRatio * size[0] / 2 - transform[4], pixelRatio * size[1] / 2 - transform[5],
70081 pixelRatio / viewResolution, -pixelRatio / viewResolution,
70082 0,
70083 -viewCenter[0], -viewCenter[1]);
70084
70085 this.updateAttributions(frameState.attributions, image.getAttributions());
70086 this.updateLogos(frameState, imageSource);
70087 this.renderedResolution = viewResolution * pixelRatio / imagePixelRatio;
70088 }
70089
70090 return !!this.image_;
70091};
70092
70093goog.provide('ol.reproj');
70094
70095goog.require('ol.dom');
70096goog.require('ol.extent');
70097goog.require('ol.math');
70098goog.require('ol.proj');
70099
70100
70101/**
70102 * Calculates ideal resolution to use from the source in order to achieve
70103 * pixel mapping as close as possible to 1:1 during reprojection.
70104 * The resolution is calculated regardless of what resolutions
70105 * are actually available in the dataset (TileGrid, Image, ...).
70106 *
70107 * @param {ol.proj.Projection} sourceProj Source projection.
70108 * @param {ol.proj.Projection} targetProj Target projection.
70109 * @param {ol.Coordinate} targetCenter Target center.
70110 * @param {number} targetResolution Target resolution.
70111 * @return {number} The best resolution to use. Can be +-Infinity, NaN or 0.
70112 */
70113ol.reproj.calculateSourceResolution = function(sourceProj, targetProj,
70114 targetCenter, targetResolution) {
70115
70116 var sourceCenter = ol.proj.transform(targetCenter, targetProj, sourceProj);
70117
70118 // calculate the ideal resolution of the source data
70119 var sourceResolution =
70120 ol.proj.getPointResolution(targetProj, targetResolution, targetCenter);
70121
70122 var targetMetersPerUnit = targetProj.getMetersPerUnit();
70123 if (targetMetersPerUnit !== undefined) {
70124 sourceResolution *= targetMetersPerUnit;
70125 }
70126 var sourceMetersPerUnit = sourceProj.getMetersPerUnit();
70127 if (sourceMetersPerUnit !== undefined) {
70128 sourceResolution /= sourceMetersPerUnit;
70129 }
70130
70131 // Based on the projection properties, the point resolution at the specified
70132 // coordinates may be slightly different. We need to reverse-compensate this
70133 // in order to achieve optimal results.
70134
70135 var sourceExtent = sourceProj.getExtent();
70136 if (!sourceExtent || ol.extent.containsCoordinate(sourceExtent, sourceCenter)) {
70137 var compensationFactor =
70138 ol.proj.getPointResolution(sourceProj, sourceResolution, sourceCenter) /
70139 sourceResolution;
70140 if (isFinite(compensationFactor) && compensationFactor > 0) {
70141 sourceResolution /= compensationFactor;
70142 }
70143 }
70144
70145 return sourceResolution;
70146};
70147
70148
70149/**
70150 * Enlarge the clipping triangle point by 1 pixel to ensure the edges overlap
70151 * in order to mask gaps caused by antialiasing.
70152 *
70153 * @param {number} centroidX Centroid of the triangle (x coordinate in pixels).
70154 * @param {number} centroidY Centroid of the triangle (y coordinate in pixels).
70155 * @param {number} x X coordinate of the point (in pixels).
70156 * @param {number} y Y coordinate of the point (in pixels).
70157 * @return {ol.Coordinate} New point 1 px farther from the centroid.
70158 * @private
70159 */
70160ol.reproj.enlargeClipPoint_ = function(centroidX, centroidY, x, y) {
70161 var dX = x - centroidX, dY = y - centroidY;
70162 var distance = Math.sqrt(dX * dX + dY * dY);
70163 return [Math.round(x + dX / distance), Math.round(y + dY / distance)];
70164};
70165
70166
70167/**
70168 * Renders the source data into new canvas based on the triangulation.
70169 *
70170 * @param {number} width Width of the canvas.
70171 * @param {number} height Height of the canvas.
70172 * @param {number} pixelRatio Pixel ratio.
70173 * @param {number} sourceResolution Source resolution.
70174 * @param {ol.Extent} sourceExtent Extent of the data source.
70175 * @param {number} targetResolution Target resolution.
70176 * @param {ol.Extent} targetExtent Target extent.
70177 * @param {ol.reproj.Triangulation} triangulation Calculated triangulation.
70178 * @param {Array.<{extent: ol.Extent,
70179 * image: (HTMLCanvasElement|Image|HTMLVideoElement)}>} sources
70180 * Array of sources.
70181 * @param {number} gutter Gutter of the sources.
70182 * @param {boolean=} opt_renderEdges Render reprojection edges.
70183 * @return {HTMLCanvasElement} Canvas with reprojected data.
70184 */
70185ol.reproj.render = function(width, height, pixelRatio,
70186 sourceResolution, sourceExtent, targetResolution, targetExtent,
70187 triangulation, sources, gutter, opt_renderEdges) {
70188
70189 var context = ol.dom.createCanvasContext2D(Math.round(pixelRatio * width),
70190 Math.round(pixelRatio * height));
70191
70192 if (sources.length === 0) {
70193 return context.canvas;
70194 }
70195
70196 context.scale(pixelRatio, pixelRatio);
70197
70198 var sourceDataExtent = ol.extent.createEmpty();
70199 sources.forEach(function(src, i, arr) {
70200 ol.extent.extend(sourceDataExtent, src.extent);
70201 });
70202
70203 var canvasWidthInUnits = ol.extent.getWidth(sourceDataExtent);
70204 var canvasHeightInUnits = ol.extent.getHeight(sourceDataExtent);
70205 var stitchContext = ol.dom.createCanvasContext2D(
70206 Math.round(pixelRatio * canvasWidthInUnits / sourceResolution),
70207 Math.round(pixelRatio * canvasHeightInUnits / sourceResolution));
70208
70209 var stitchScale = pixelRatio / sourceResolution;
70210
70211 sources.forEach(function(src, i, arr) {
70212 var xPos = src.extent[0] - sourceDataExtent[0];
70213 var yPos = -(src.extent[3] - sourceDataExtent[3]);
70214 var srcWidth = ol.extent.getWidth(src.extent);
70215 var srcHeight = ol.extent.getHeight(src.extent);
70216
70217 stitchContext.drawImage(
70218 src.image,
70219 gutter, gutter,
70220 src.image.width - 2 * gutter, src.image.height - 2 * gutter,
70221 xPos * stitchScale, yPos * stitchScale,
70222 srcWidth * stitchScale, srcHeight * stitchScale);
70223 });
70224
70225 var targetTopLeft = ol.extent.getTopLeft(targetExtent);
70226
70227 triangulation.getTriangles().forEach(function(triangle, i, arr) {
70228 /* Calculate affine transform (src -> dst)
70229 * Resulting matrix can be used to transform coordinate
70230 * from `sourceProjection` to destination pixels.
70231 *
70232 * To optimize number of context calls and increase numerical stability,
70233 * we also do the following operations:
70234 * trans(-topLeftExtentCorner), scale(1 / targetResolution), scale(1, -1)
70235 * here before solving the linear system so [ui, vi] are pixel coordinates.
70236 *
70237 * Src points: xi, yi
70238 * Dst points: ui, vi
70239 * Affine coefficients: aij
70240 *
70241 * | x0 y0 1 0 0 0 | |a00| |u0|
70242 * | x1 y1 1 0 0 0 | |a01| |u1|
70243 * | x2 y2 1 0 0 0 | x |a02| = |u2|
70244 * | 0 0 0 x0 y0 1 | |a10| |v0|
70245 * | 0 0 0 x1 y1 1 | |a11| |v1|
70246 * | 0 0 0 x2 y2 1 | |a12| |v2|
70247 */
70248 var source = triangle.source, target = triangle.target;
70249 var x0 = source[0][0], y0 = source[0][1],
70250 x1 = source[1][0], y1 = source[1][1],
70251 x2 = source[2][0], y2 = source[2][1];
70252 var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,
70253 v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;
70254 var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,
70255 v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;
70256 var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,
70257 v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;
70258
70259 // Shift all the source points to improve numerical stability
70260 // of all the subsequent calculations. The [x0, y0] is used here.
70261 // This is also used to simplify the linear system.
70262 var sourceNumericalShiftX = x0, sourceNumericalShiftY = y0;
70263 x0 = 0;
70264 y0 = 0;
70265 x1 -= sourceNumericalShiftX;
70266 y1 -= sourceNumericalShiftY;
70267 x2 -= sourceNumericalShiftX;
70268 y2 -= sourceNumericalShiftY;
70269
70270 var augmentedMatrix = [
70271 [x1, y1, 0, 0, u1 - u0],
70272 [x2, y2, 0, 0, u2 - u0],
70273 [0, 0, x1, y1, v1 - v0],
70274 [0, 0, x2, y2, v2 - v0]
70275 ];
70276 var affineCoefs = ol.math.solveLinearSystem(augmentedMatrix);
70277 if (!affineCoefs) {
70278 return;
70279 }
70280
70281 context.save();
70282 context.beginPath();
70283 var centroidX = (u0 + u1 + u2) / 3, centroidY = (v0 + v1 + v2) / 3;
70284 var p0 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u0, v0);
70285 var p1 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u1, v1);
70286 var p2 = ol.reproj.enlargeClipPoint_(centroidX, centroidY, u2, v2);
70287
70288 context.moveTo(p1[0], p1[1]);
70289 context.lineTo(p0[0], p0[1]);
70290 context.lineTo(p2[0], p2[1]);
70291 context.clip();
70292
70293 context.transform(
70294 affineCoefs[0], affineCoefs[2], affineCoefs[1], affineCoefs[3], u0, v0);
70295
70296 context.translate(sourceDataExtent[0] - sourceNumericalShiftX,
70297 sourceDataExtent[3] - sourceNumericalShiftY);
70298
70299 context.scale(sourceResolution / pixelRatio,
70300 -sourceResolution / pixelRatio);
70301
70302 context.drawImage(stitchContext.canvas, 0, 0);
70303 context.restore();
70304 });
70305
70306 if (opt_renderEdges) {
70307 context.save();
70308
70309 context.strokeStyle = 'black';
70310 context.lineWidth = 1;
70311
70312 triangulation.getTriangles().forEach(function(triangle, i, arr) {
70313 var target = triangle.target;
70314 var u0 = (target[0][0] - targetTopLeft[0]) / targetResolution,
70315 v0 = -(target[0][1] - targetTopLeft[1]) / targetResolution;
70316 var u1 = (target[1][0] - targetTopLeft[0]) / targetResolution,
70317 v1 = -(target[1][1] - targetTopLeft[1]) / targetResolution;
70318 var u2 = (target[2][0] - targetTopLeft[0]) / targetResolution,
70319 v2 = -(target[2][1] - targetTopLeft[1]) / targetResolution;
70320
70321 context.beginPath();
70322 context.moveTo(u1, v1);
70323 context.lineTo(u0, v0);
70324 context.lineTo(u2, v2);
70325 context.closePath();
70326 context.stroke();
70327 });
70328
70329 context.restore();
70330 }
70331 return context.canvas;
70332};
70333
70334goog.provide('ol.reproj.Triangulation');
70335
70336goog.require('ol');
70337goog.require('ol.extent');
70338goog.require('ol.math');
70339goog.require('ol.proj');
70340
70341
70342/**
70343 * @classdesc
70344 * Class containing triangulation of the given target extent.
70345 * Used for determining source data and the reprojection itself.
70346 *
70347 * @param {ol.proj.Projection} sourceProj Source projection.
70348 * @param {ol.proj.Projection} targetProj Target projection.
70349 * @param {ol.Extent} targetExtent Target extent to triangulate.
70350 * @param {ol.Extent} maxSourceExtent Maximal source extent that can be used.
70351 * @param {number} errorThreshold Acceptable error (in source units).
70352 * @constructor
70353 */
70354ol.reproj.Triangulation = function(sourceProj, targetProj, targetExtent,
70355 maxSourceExtent, errorThreshold) {
70356
70357 /**
70358 * @type {ol.proj.Projection}
70359 * @private
70360 */
70361 this.sourceProj_ = sourceProj;
70362
70363 /**
70364 * @type {ol.proj.Projection}
70365 * @private
70366 */
70367 this.targetProj_ = targetProj;
70368
70369 /** @type {!Object.<string, ol.Coordinate>} */
70370 var transformInvCache = {};
70371 var transformInv = ol.proj.getTransform(this.targetProj_, this.sourceProj_);
70372
70373 /**
70374 * @param {ol.Coordinate} c A coordinate.
70375 * @return {ol.Coordinate} Transformed coordinate.
70376 * @private
70377 */
70378 this.transformInv_ = function(c) {
70379 var key = c[0] + '/' + c[1];
70380 if (!transformInvCache[key]) {
70381 transformInvCache[key] = transformInv(c);
70382 }
70383 return transformInvCache[key];
70384 };
70385
70386 /**
70387 * @type {ol.Extent}
70388 * @private
70389 */
70390 this.maxSourceExtent_ = maxSourceExtent;
70391
70392 /**
70393 * @type {number}
70394 * @private
70395 */
70396 this.errorThresholdSquared_ = errorThreshold * errorThreshold;
70397
70398 /**
70399 * @type {Array.<ol.ReprojTriangle>}
70400 * @private
70401 */
70402 this.triangles_ = [];
70403
70404 /**
70405 * Indicates that the triangulation crosses edge of the source projection.
70406 * @type {boolean}
70407 * @private
70408 */
70409 this.wrapsXInSource_ = false;
70410
70411 /**
70412 * @type {boolean}
70413 * @private
70414 */
70415 this.canWrapXInSource_ = this.sourceProj_.canWrapX() &&
70416 !!maxSourceExtent &&
70417 !!this.sourceProj_.getExtent() &&
70418 (ol.extent.getWidth(maxSourceExtent) ==
70419 ol.extent.getWidth(this.sourceProj_.getExtent()));
70420
70421 /**
70422 * @type {?number}
70423 * @private
70424 */
70425 this.sourceWorldWidth_ = this.sourceProj_.getExtent() ?
70426 ol.extent.getWidth(this.sourceProj_.getExtent()) : null;
70427
70428 /**
70429 * @type {?number}
70430 * @private
70431 */
70432 this.targetWorldWidth_ = this.targetProj_.getExtent() ?
70433 ol.extent.getWidth(this.targetProj_.getExtent()) : null;
70434
70435 var destinationTopLeft = ol.extent.getTopLeft(targetExtent);
70436 var destinationTopRight = ol.extent.getTopRight(targetExtent);
70437 var destinationBottomRight = ol.extent.getBottomRight(targetExtent);
70438 var destinationBottomLeft = ol.extent.getBottomLeft(targetExtent);
70439 var sourceTopLeft = this.transformInv_(destinationTopLeft);
70440 var sourceTopRight = this.transformInv_(destinationTopRight);
70441 var sourceBottomRight = this.transformInv_(destinationBottomRight);
70442 var sourceBottomLeft = this.transformInv_(destinationBottomLeft);
70443
70444 this.addQuad_(
70445 destinationTopLeft, destinationTopRight,
70446 destinationBottomRight, destinationBottomLeft,
70447 sourceTopLeft, sourceTopRight, sourceBottomRight, sourceBottomLeft,
70448 ol.RASTER_REPROJECTION_MAX_SUBDIVISION);
70449
70450 if (this.wrapsXInSource_) {
70451 var leftBound = Infinity;
70452 this.triangles_.forEach(function(triangle, i, arr) {
70453 leftBound = Math.min(leftBound,
70454 triangle.source[0][0], triangle.source[1][0], triangle.source[2][0]);
70455 });
70456
70457 // Shift triangles to be as close to `leftBound` as possible
70458 // (if the distance is more than `worldWidth / 2` it can be closer.
70459 this.triangles_.forEach(function(triangle) {
70460 if (Math.max(triangle.source[0][0], triangle.source[1][0],
70461 triangle.source[2][0]) - leftBound > this.sourceWorldWidth_ / 2) {
70462 var newTriangle = [[triangle.source[0][0], triangle.source[0][1]],
70463 [triangle.source[1][0], triangle.source[1][1]],
70464 [triangle.source[2][0], triangle.source[2][1]]];
70465 if ((newTriangle[0][0] - leftBound) > this.sourceWorldWidth_ / 2) {
70466 newTriangle[0][0] -= this.sourceWorldWidth_;
70467 }
70468 if ((newTriangle[1][0] - leftBound) > this.sourceWorldWidth_ / 2) {
70469 newTriangle[1][0] -= this.sourceWorldWidth_;
70470 }
70471 if ((newTriangle[2][0] - leftBound) > this.sourceWorldWidth_ / 2) {
70472 newTriangle[2][0] -= this.sourceWorldWidth_;
70473 }
70474
70475 // Rarely (if the extent contains both the dateline and prime meridian)
70476 // the shift can in turn break some triangles.
70477 // Detect this here and don't shift in such cases.
70478 var minX = Math.min(
70479 newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);
70480 var maxX = Math.max(
70481 newTriangle[0][0], newTriangle[1][0], newTriangle[2][0]);
70482 if ((maxX - minX) < this.sourceWorldWidth_ / 2) {
70483 triangle.source = newTriangle;
70484 }
70485 }
70486 }, this);
70487 }
70488
70489 transformInvCache = {};
70490};
70491
70492
70493/**
70494 * Adds triangle to the triangulation.
70495 * @param {ol.Coordinate} a The target a coordinate.
70496 * @param {ol.Coordinate} b The target b coordinate.
70497 * @param {ol.Coordinate} c The target c coordinate.
70498 * @param {ol.Coordinate} aSrc The source a coordinate.
70499 * @param {ol.Coordinate} bSrc The source b coordinate.
70500 * @param {ol.Coordinate} cSrc The source c coordinate.
70501 * @private
70502 */
70503ol.reproj.Triangulation.prototype.addTriangle_ = function(a, b, c,
70504 aSrc, bSrc, cSrc) {
70505 this.triangles_.push({
70506 source: [aSrc, bSrc, cSrc],
70507 target: [a, b, c]
70508 });
70509};
70510
70511
70512/**
70513 * Adds quad (points in clock-wise order) to the triangulation
70514 * (and reprojects the vertices) if valid.
70515 * Performs quad subdivision if needed to increase precision.
70516 *
70517 * @param {ol.Coordinate} a The target a coordinate.
70518 * @param {ol.Coordinate} b The target b coordinate.
70519 * @param {ol.Coordinate} c The target c coordinate.
70520 * @param {ol.Coordinate} d The target d coordinate.
70521 * @param {ol.Coordinate} aSrc The source a coordinate.
70522 * @param {ol.Coordinate} bSrc The source b coordinate.
70523 * @param {ol.Coordinate} cSrc The source c coordinate.
70524 * @param {ol.Coordinate} dSrc The source d coordinate.
70525 * @param {number} maxSubdivision Maximal allowed subdivision of the quad.
70526 * @private
70527 */
70528ol.reproj.Triangulation.prototype.addQuad_ = function(a, b, c, d,
70529 aSrc, bSrc, cSrc, dSrc, maxSubdivision) {
70530
70531 var sourceQuadExtent = ol.extent.boundingExtent([aSrc, bSrc, cSrc, dSrc]);
70532 var sourceCoverageX = this.sourceWorldWidth_ ?
70533 ol.extent.getWidth(sourceQuadExtent) / this.sourceWorldWidth_ : null;
70534 var sourceWorldWidth = /** @type {number} */ (this.sourceWorldWidth_);
70535
70536 // when the quad is wrapped in the source projection
70537 // it covers most of the projection extent, but not fully
70538 var wrapsX = this.sourceProj_.canWrapX() &&
70539 sourceCoverageX > 0.5 && sourceCoverageX < 1;
70540
70541 var needsSubdivision = false;
70542
70543 if (maxSubdivision > 0) {
70544 if (this.targetProj_.isGlobal() && this.targetWorldWidth_) {
70545 var targetQuadExtent = ol.extent.boundingExtent([a, b, c, d]);
70546 var targetCoverageX =
70547 ol.extent.getWidth(targetQuadExtent) / this.targetWorldWidth_;
70548 needsSubdivision |=
70549 targetCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;
70550 }
70551 if (!wrapsX && this.sourceProj_.isGlobal() && sourceCoverageX) {
70552 needsSubdivision |=
70553 sourceCoverageX > ol.RASTER_REPROJECTION_MAX_TRIANGLE_WIDTH;
70554 }
70555 }
70556
70557 if (!needsSubdivision && this.maxSourceExtent_) {
70558 if (!ol.extent.intersects(sourceQuadExtent, this.maxSourceExtent_)) {
70559 // whole quad outside source projection extent -> ignore
70560 return;
70561 }
70562 }
70563
70564 if (!needsSubdivision) {
70565 if (!isFinite(aSrc[0]) || !isFinite(aSrc[1]) ||
70566 !isFinite(bSrc[0]) || !isFinite(bSrc[1]) ||
70567 !isFinite(cSrc[0]) || !isFinite(cSrc[1]) ||
70568 !isFinite(dSrc[0]) || !isFinite(dSrc[1])) {
70569 if (maxSubdivision > 0) {
70570 needsSubdivision = true;
70571 } else {
70572 return;
70573 }
70574 }
70575 }
70576
70577 if (maxSubdivision > 0) {
70578 if (!needsSubdivision) {
70579 var center = [(a[0] + c[0]) / 2, (a[1] + c[1]) / 2];
70580 var centerSrc = this.transformInv_(center);
70581
70582 var dx;
70583 if (wrapsX) {
70584 var centerSrcEstimX =
70585 (ol.math.modulo(aSrc[0], sourceWorldWidth) +
70586 ol.math.modulo(cSrc[0], sourceWorldWidth)) / 2;
70587 dx = centerSrcEstimX -
70588 ol.math.modulo(centerSrc[0], sourceWorldWidth);
70589 } else {
70590 dx = (aSrc[0] + cSrc[0]) / 2 - centerSrc[0];
70591 }
70592 var dy = (aSrc[1] + cSrc[1]) / 2 - centerSrc[1];
70593 var centerSrcErrorSquared = dx * dx + dy * dy;
70594 needsSubdivision = centerSrcErrorSquared > this.errorThresholdSquared_;
70595 }
70596 if (needsSubdivision) {
70597 if (Math.abs(a[0] - c[0]) <= Math.abs(a[1] - c[1])) {
70598 // split horizontally (top & bottom)
70599 var bc = [(b[0] + c[0]) / 2, (b[1] + c[1]) / 2];
70600 var bcSrc = this.transformInv_(bc);
70601 var da = [(d[0] + a[0]) / 2, (d[1] + a[1]) / 2];
70602 var daSrc = this.transformInv_(da);
70603
70604 this.addQuad_(
70605 a, b, bc, da, aSrc, bSrc, bcSrc, daSrc, maxSubdivision - 1);
70606 this.addQuad_(
70607 da, bc, c, d, daSrc, bcSrc, cSrc, dSrc, maxSubdivision - 1);
70608 } else {
70609 // split vertically (left & right)
70610 var ab = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
70611 var abSrc = this.transformInv_(ab);
70612 var cd = [(c[0] + d[0]) / 2, (c[1] + d[1]) / 2];
70613 var cdSrc = this.transformInv_(cd);
70614
70615 this.addQuad_(
70616 a, ab, cd, d, aSrc, abSrc, cdSrc, dSrc, maxSubdivision - 1);
70617 this.addQuad_(
70618 ab, b, c, cd, abSrc, bSrc, cSrc, cdSrc, maxSubdivision - 1);
70619 }
70620 return;
70621 }
70622 }
70623
70624 if (wrapsX) {
70625 if (!this.canWrapXInSource_) {
70626 return;
70627 }
70628 this.wrapsXInSource_ = true;
70629 }
70630
70631 this.addTriangle_(a, c, d, aSrc, cSrc, dSrc);
70632 this.addTriangle_(a, b, c, aSrc, bSrc, cSrc);
70633};
70634
70635
70636/**
70637 * Calculates extent of the 'source' coordinates from all the triangles.
70638 *
70639 * @return {ol.Extent} Calculated extent.
70640 */
70641ol.reproj.Triangulation.prototype.calculateSourceExtent = function() {
70642 var extent = ol.extent.createEmpty();
70643
70644 this.triangles_.forEach(function(triangle, i, arr) {
70645 var src = triangle.source;
70646 ol.extent.extendCoordinate(extent, src[0]);
70647 ol.extent.extendCoordinate(extent, src[1]);
70648 ol.extent.extendCoordinate(extent, src[2]);
70649 });
70650
70651 return extent;
70652};
70653
70654
70655/**
70656 * @return {Array.<ol.ReprojTriangle>} Array of the calculated triangles.
70657 */
70658ol.reproj.Triangulation.prototype.getTriangles = function() {
70659 return this.triangles_;
70660};
70661
70662goog.provide('ol.reproj.Image');
70663
70664goog.require('ol');
70665goog.require('ol.ImageBase');
70666goog.require('ol.ImageState');
70667goog.require('ol.events');
70668goog.require('ol.events.EventType');
70669goog.require('ol.extent');
70670goog.require('ol.reproj');
70671goog.require('ol.reproj.Triangulation');
70672
70673
70674/**
70675 * @classdesc
70676 * Class encapsulating single reprojected image.
70677 * See {@link ol.source.Image}.
70678 *
70679 * @constructor
70680 * @extends {ol.ImageBase}
70681 * @param {ol.proj.Projection} sourceProj Source projection (of the data).
70682 * @param {ol.proj.Projection} targetProj Target projection.
70683 * @param {ol.Extent} targetExtent Target extent.
70684 * @param {number} targetResolution Target resolution.
70685 * @param {number} pixelRatio Pixel ratio.
70686 * @param {ol.ReprojImageFunctionType} getImageFunction
70687 * Function returning source images (extent, resolution, pixelRatio).
70688 */
70689ol.reproj.Image = function(sourceProj, targetProj,
70690 targetExtent, targetResolution, pixelRatio, getImageFunction) {
70691
70692 /**
70693 * @private
70694 * @type {ol.proj.Projection}
70695 */
70696 this.targetProj_ = targetProj;
70697
70698 /**
70699 * @private
70700 * @type {ol.Extent}
70701 */
70702 this.maxSourceExtent_ = sourceProj.getExtent();
70703 var maxTargetExtent = targetProj.getExtent();
70704
70705 var limitedTargetExtent = maxTargetExtent ?
70706 ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;
70707
70708 var targetCenter = ol.extent.getCenter(limitedTargetExtent);
70709 var sourceResolution = ol.reproj.calculateSourceResolution(
70710 sourceProj, targetProj, targetCenter, targetResolution);
70711
70712 var errorThresholdInPixels = ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;
70713
70714 /**
70715 * @private
70716 * @type {!ol.reproj.Triangulation}
70717 */
70718 this.triangulation_ = new ol.reproj.Triangulation(
70719 sourceProj, targetProj, limitedTargetExtent, this.maxSourceExtent_,
70720 sourceResolution * errorThresholdInPixels);
70721
70722 /**
70723 * @private
70724 * @type {number}
70725 */
70726 this.targetResolution_ = targetResolution;
70727
70728 /**
70729 * @private
70730 * @type {ol.Extent}
70731 */
70732 this.targetExtent_ = targetExtent;
70733
70734 var sourceExtent = this.triangulation_.calculateSourceExtent();
70735
70736 /**
70737 * @private
70738 * @type {ol.ImageBase}
70739 */
70740 this.sourceImage_ =
70741 getImageFunction(sourceExtent, sourceResolution, pixelRatio);
70742
70743 /**
70744 * @private
70745 * @type {number}
70746 */
70747 this.sourcePixelRatio_ =
70748 this.sourceImage_ ? this.sourceImage_.getPixelRatio() : 1;
70749
70750 /**
70751 * @private
70752 * @type {HTMLCanvasElement}
70753 */
70754 this.canvas_ = null;
70755
70756 /**
70757 * @private
70758 * @type {?ol.EventsKey}
70759 */
70760 this.sourceListenerKey_ = null;
70761
70762
70763 var state = ol.ImageState.LOADED;
70764 var attributions = [];
70765
70766 if (this.sourceImage_) {
70767 state = ol.ImageState.IDLE;
70768 attributions = this.sourceImage_.getAttributions();
70769 }
70770
70771 ol.ImageBase.call(this, targetExtent, targetResolution, this.sourcePixelRatio_,
70772 state, attributions);
70773};
70774ol.inherits(ol.reproj.Image, ol.ImageBase);
70775
70776
70777/**
70778 * @inheritDoc
70779 */
70780ol.reproj.Image.prototype.disposeInternal = function() {
70781 if (this.state == ol.ImageState.LOADING) {
70782 this.unlistenSource_();
70783 }
70784 ol.ImageBase.prototype.disposeInternal.call(this);
70785};
70786
70787
70788/**
70789 * @inheritDoc
70790 */
70791ol.reproj.Image.prototype.getImage = function(opt_context) {
70792 return this.canvas_;
70793};
70794
70795
70796/**
70797 * @return {ol.proj.Projection} Projection.
70798 */
70799ol.reproj.Image.prototype.getProjection = function() {
70800 return this.targetProj_;
70801};
70802
70803
70804/**
70805 * @private
70806 */
70807ol.reproj.Image.prototype.reproject_ = function() {
70808 var sourceState = this.sourceImage_.getState();
70809 if (sourceState == ol.ImageState.LOADED) {
70810 var width = ol.extent.getWidth(this.targetExtent_) / this.targetResolution_;
70811 var height =
70812 ol.extent.getHeight(this.targetExtent_) / this.targetResolution_;
70813
70814 this.canvas_ = ol.reproj.render(width, height, this.sourcePixelRatio_,
70815 this.sourceImage_.getResolution(), this.maxSourceExtent_,
70816 this.targetResolution_, this.targetExtent_, this.triangulation_, [{
70817 extent: this.sourceImage_.getExtent(),
70818 image: this.sourceImage_.getImage()
70819 }], 0);
70820 }
70821 this.state = sourceState;
70822 this.changed();
70823};
70824
70825
70826/**
70827 * @inheritDoc
70828 */
70829ol.reproj.Image.prototype.load = function() {
70830 if (this.state == ol.ImageState.IDLE) {
70831 this.state = ol.ImageState.LOADING;
70832 this.changed();
70833
70834 var sourceState = this.sourceImage_.getState();
70835 if (sourceState == ol.ImageState.LOADED ||
70836 sourceState == ol.ImageState.ERROR) {
70837 this.reproject_();
70838 } else {
70839 this.sourceListenerKey_ = ol.events.listen(this.sourceImage_,
70840 ol.events.EventType.CHANGE, function(e) {
70841 var sourceState = this.sourceImage_.getState();
70842 if (sourceState == ol.ImageState.LOADED ||
70843 sourceState == ol.ImageState.ERROR) {
70844 this.unlistenSource_();
70845 this.reproject_();
70846 }
70847 }, this);
70848 this.sourceImage_.load();
70849 }
70850 }
70851};
70852
70853
70854/**
70855 * @private
70856 */
70857ol.reproj.Image.prototype.unlistenSource_ = function() {
70858 ol.events.unlistenByKey(/** @type {!ol.EventsKey} */ (this.sourceListenerKey_));
70859 this.sourceListenerKey_ = null;
70860};
70861
70862goog.provide('ol.source.Image');
70863
70864goog.require('ol');
70865goog.require('ol.ImageState');
70866goog.require('ol.array');
70867goog.require('ol.events.Event');
70868goog.require('ol.extent');
70869goog.require('ol.proj');
70870goog.require('ol.reproj.Image');
70871goog.require('ol.source.Source');
70872
70873
70874/**
70875 * @classdesc
70876 * Abstract base class; normally only used for creating subclasses and not
70877 * instantiated in apps.
70878 * Base class for sources providing a single image.
70879 *
70880 * @constructor
70881 * @abstract
70882 * @extends {ol.source.Source}
70883 * @param {ol.SourceImageOptions} options Single image source options.
70884 * @api
70885 */
70886ol.source.Image = function(options) {
70887 ol.source.Source.call(this, {
70888 attributions: options.attributions,
70889 extent: options.extent,
70890 logo: options.logo,
70891 projection: options.projection,
70892 state: options.state
70893 });
70894
70895 /**
70896 * @private
70897 * @type {Array.<number>}
70898 */
70899 this.resolutions_ = options.resolutions !== undefined ?
70900 options.resolutions : null;
70901
70902
70903 /**
70904 * @private
70905 * @type {ol.reproj.Image}
70906 */
70907 this.reprojectedImage_ = null;
70908
70909
70910 /**
70911 * @private
70912 * @type {number}
70913 */
70914 this.reprojectedRevision_ = 0;
70915};
70916ol.inherits(ol.source.Image, ol.source.Source);
70917
70918
70919/**
70920 * @return {Array.<number>} Resolutions.
70921 * @override
70922 */
70923ol.source.Image.prototype.getResolutions = function() {
70924 return this.resolutions_;
70925};
70926
70927
70928/**
70929 * @protected
70930 * @param {number} resolution Resolution.
70931 * @return {number} Resolution.
70932 */
70933ol.source.Image.prototype.findNearestResolution = function(resolution) {
70934 if (this.resolutions_) {
70935 var idx = ol.array.linearFindNearest(this.resolutions_, resolution, 0);
70936 resolution = this.resolutions_[idx];
70937 }
70938 return resolution;
70939};
70940
70941
70942/**
70943 * @param {ol.Extent} extent Extent.
70944 * @param {number} resolution Resolution.
70945 * @param {number} pixelRatio Pixel ratio.
70946 * @param {ol.proj.Projection} projection Projection.
70947 * @return {ol.ImageBase} Single image.
70948 */
70949ol.source.Image.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
70950 var sourceProjection = this.getProjection();
70951 if (!ol.ENABLE_RASTER_REPROJECTION ||
70952 !sourceProjection ||
70953 !projection ||
70954 ol.proj.equivalent(sourceProjection, projection)) {
70955 if (sourceProjection) {
70956 projection = sourceProjection;
70957 }
70958 return this.getImageInternal(extent, resolution, pixelRatio, projection);
70959 } else {
70960 if (this.reprojectedImage_) {
70961 if (this.reprojectedRevision_ == this.getRevision() &&
70962 ol.proj.equivalent(
70963 this.reprojectedImage_.getProjection(), projection) &&
70964 this.reprojectedImage_.getResolution() == resolution &&
70965 ol.extent.equals(this.reprojectedImage_.getExtent(), extent)) {
70966 return this.reprojectedImage_;
70967 }
70968 this.reprojectedImage_.dispose();
70969 this.reprojectedImage_ = null;
70970 }
70971
70972 this.reprojectedImage_ = new ol.reproj.Image(
70973 sourceProjection, projection, extent, resolution, pixelRatio,
70974 function(extent, resolution, pixelRatio) {
70975 return this.getImageInternal(extent, resolution,
70976 pixelRatio, sourceProjection);
70977 }.bind(this));
70978 this.reprojectedRevision_ = this.getRevision();
70979
70980 return this.reprojectedImage_;
70981 }
70982};
70983
70984
70985/**
70986 * @abstract
70987 * @param {ol.Extent} extent Extent.
70988 * @param {number} resolution Resolution.
70989 * @param {number} pixelRatio Pixel ratio.
70990 * @param {ol.proj.Projection} projection Projection.
70991 * @return {ol.ImageBase} Single image.
70992 * @protected
70993 */
70994ol.source.Image.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {};
70995
70996
70997/**
70998 * Handle image change events.
70999 * @param {ol.events.Event} event Event.
71000 * @protected
71001 */
71002ol.source.Image.prototype.handleImageChange = function(event) {
71003 var image = /** @type {ol.Image} */ (event.target);
71004 switch (image.getState()) {
71005 case ol.ImageState.LOADING:
71006 this.dispatchEvent(
71007 new ol.source.Image.Event(ol.source.Image.EventType_.IMAGELOADSTART,
71008 image));
71009 break;
71010 case ol.ImageState.LOADED:
71011 this.dispatchEvent(
71012 new ol.source.Image.Event(ol.source.Image.EventType_.IMAGELOADEND,
71013 image));
71014 break;
71015 case ol.ImageState.ERROR:
71016 this.dispatchEvent(
71017 new ol.source.Image.Event(ol.source.Image.EventType_.IMAGELOADERROR,
71018 image));
71019 break;
71020 default:
71021 // pass
71022 }
71023};
71024
71025
71026/**
71027 * Default image load function for image sources that use ol.Image image
71028 * instances.
71029 * @param {ol.Image} image Image.
71030 * @param {string} src Source.
71031 */
71032ol.source.Image.defaultImageLoadFunction = function(image, src) {
71033 image.getImage().src = src;
71034};
71035
71036
71037/**
71038 * @classdesc
71039 * Events emitted by {@link ol.source.Image} instances are instances of this
71040 * type.
71041 *
71042 * @constructor
71043 * @extends {ol.events.Event}
71044 * @implements {oli.source.ImageEvent}
71045 * @param {string} type Type.
71046 * @param {ol.Image} image The image.
71047 */
71048ol.source.Image.Event = function(type, image) {
71049
71050 ol.events.Event.call(this, type);
71051
71052 /**
71053 * The image related to the event.
71054 * @type {ol.Image}
71055 * @api
71056 */
71057 this.image = image;
71058
71059};
71060ol.inherits(ol.source.Image.Event, ol.events.Event);
71061
71062
71063/**
71064 * @enum {string}
71065 * @private
71066 */
71067ol.source.Image.EventType_ = {
71068
71069 /**
71070 * Triggered when an image starts loading.
71071 * @event ol.source.Image.Event#imageloadstart
71072 * @api
71073 */
71074 IMAGELOADSTART: 'imageloadstart',
71075
71076 /**
71077 * Triggered when an image finishes loading.
71078 * @event ol.source.Image.Event#imageloadend
71079 * @api
71080 */
71081 IMAGELOADEND: 'imageloadend',
71082
71083 /**
71084 * Triggered if image loading results in an error.
71085 * @event ol.source.Image.Event#imageloaderror
71086 * @api
71087 */
71088 IMAGELOADERROR: 'imageloaderror'
71089
71090};
71091
71092goog.provide('ol.source.ImageCanvas');
71093
71094goog.require('ol');
71095goog.require('ol.ImageCanvas');
71096goog.require('ol.extent');
71097goog.require('ol.source.Image');
71098
71099
71100/**
71101 * @classdesc
71102 * Base class for image sources where a canvas element is the image.
71103 *
71104 * @constructor
71105 * @extends {ol.source.Image}
71106 * @param {olx.source.ImageCanvasOptions} options Constructor options.
71107 * @api
71108 */
71109ol.source.ImageCanvas = function(options) {
71110
71111 ol.source.Image.call(this, {
71112 attributions: options.attributions,
71113 logo: options.logo,
71114 projection: options.projection,
71115 resolutions: options.resolutions,
71116 state: options.state
71117 });
71118
71119 /**
71120 * @private
71121 * @type {ol.CanvasFunctionType}
71122 */
71123 this.canvasFunction_ = options.canvasFunction;
71124
71125 /**
71126 * @private
71127 * @type {ol.ImageCanvas}
71128 */
71129 this.canvas_ = null;
71130
71131 /**
71132 * @private
71133 * @type {number}
71134 */
71135 this.renderedRevision_ = 0;
71136
71137 /**
71138 * @private
71139 * @type {number}
71140 */
71141 this.ratio_ = options.ratio !== undefined ?
71142 options.ratio : 1.5;
71143
71144};
71145ol.inherits(ol.source.ImageCanvas, ol.source.Image);
71146
71147
71148/**
71149 * @inheritDoc
71150 */
71151ol.source.ImageCanvas.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
71152 resolution = this.findNearestResolution(resolution);
71153
71154 var canvas = this.canvas_;
71155 if (canvas &&
71156 this.renderedRevision_ == this.getRevision() &&
71157 canvas.getResolution() == resolution &&
71158 canvas.getPixelRatio() == pixelRatio &&
71159 ol.extent.containsExtent(canvas.getExtent(), extent)) {
71160 return canvas;
71161 }
71162
71163 extent = extent.slice();
71164 ol.extent.scaleFromCenter(extent, this.ratio_);
71165 var width = ol.extent.getWidth(extent) / resolution;
71166 var height = ol.extent.getHeight(extent) / resolution;
71167 var size = [width * pixelRatio, height * pixelRatio];
71168
71169 var canvasElement = this.canvasFunction_(
71170 extent, resolution, pixelRatio, size, projection);
71171 if (canvasElement) {
71172 canvas = new ol.ImageCanvas(extent, resolution, pixelRatio,
71173 this.getAttributions(), canvasElement);
71174 }
71175 this.canvas_ = canvas;
71176 this.renderedRevision_ = this.getRevision();
71177
71178 return canvas;
71179};
71180
71181goog.provide('ol.source.ImageVector');
71182
71183goog.require('ol');
71184goog.require('ol.dom');
71185goog.require('ol.events');
71186goog.require('ol.events.EventType');
71187goog.require('ol.extent');
71188goog.require('ol.render.canvas.ReplayGroup');
71189goog.require('ol.renderer.vector');
71190goog.require('ol.source.ImageCanvas');
71191goog.require('ol.style.Style');
71192goog.require('ol.transform');
71193
71194
71195/**
71196 * @classdesc
71197 * An image source whose images are canvas elements into which vector features
71198 * read from a vector source (`ol.source.Vector`) are drawn. An
71199 * `ol.source.ImageVector` object is to be used as the `source` of an image
71200 * layer (`ol.layer.Image`). Image layers are rotated, scaled, and translated,
71201 * as opposed to being re-rendered, during animations and interactions. So, like
71202 * any other image layer, an image layer configured with an
71203 * `ol.source.ImageVector` will exhibit this behaviour. This is in contrast to a
71204 * vector layer, where vector features are re-drawn during animations and
71205 * interactions.
71206 *
71207 * @constructor
71208 * @extends {ol.source.ImageCanvas}
71209 * @param {olx.source.ImageVectorOptions} options Options.
71210 * @api
71211 */
71212ol.source.ImageVector = function(options) {
71213
71214 /**
71215 * @private
71216 * @type {ol.source.Vector}
71217 */
71218 this.source_ = options.source;
71219
71220 /**
71221 * @private
71222 * @type {ol.Transform}
71223 */
71224 this.transform_ = ol.transform.create();
71225
71226 /**
71227 * @private
71228 * @type {CanvasRenderingContext2D}
71229 */
71230 this.canvasContext_ = ol.dom.createCanvasContext2D();
71231
71232 /**
71233 * @private
71234 * @type {ol.Size}
71235 */
71236 this.canvasSize_ = [0, 0];
71237
71238 /**
71239 * @private
71240 * @type {number}
71241 */
71242 this.renderBuffer_ = options.renderBuffer == undefined ? 100 : options.renderBuffer;
71243
71244 /**
71245 * @private
71246 * @type {ol.render.canvas.ReplayGroup}
71247 */
71248 this.replayGroup_ = null;
71249
71250 ol.source.ImageCanvas.call(this, {
71251 attributions: options.attributions,
71252 canvasFunction: this.canvasFunctionInternal_.bind(this),
71253 logo: options.logo,
71254 projection: options.projection,
71255 ratio: options.ratio,
71256 resolutions: options.resolutions,
71257 state: this.source_.getState()
71258 });
71259
71260 /**
71261 * User provided style.
71262 * @type {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
71263 * @private
71264 */
71265 this.style_ = null;
71266
71267 /**
71268 * Style function for use within the library.
71269 * @type {ol.StyleFunction|undefined}
71270 * @private
71271 */
71272 this.styleFunction_ = undefined;
71273
71274 this.setStyle(options.style);
71275
71276 ol.events.listen(this.source_, ol.events.EventType.CHANGE,
71277 this.handleSourceChange_, this);
71278
71279};
71280ol.inherits(ol.source.ImageVector, ol.source.ImageCanvas);
71281
71282
71283/**
71284 * @param {ol.Extent} extent Extent.
71285 * @param {number} resolution Resolution.
71286 * @param {number} pixelRatio Pixel ratio.
71287 * @param {ol.Size} size Size.
71288 * @param {ol.proj.Projection} projection Projection;
71289 * @return {HTMLCanvasElement} Canvas element.
71290 * @private
71291 */
71292ol.source.ImageVector.prototype.canvasFunctionInternal_ = function(extent, resolution, pixelRatio, size, projection) {
71293
71294 var replayGroup = new ol.render.canvas.ReplayGroup(
71295 ol.renderer.vector.getTolerance(resolution, pixelRatio), extent,
71296 resolution, this.source_.getOverlaps(), this.renderBuffer_);
71297
71298 this.source_.loadFeatures(extent, resolution, projection);
71299
71300 var loading = false;
71301 this.source_.forEachFeatureInExtent(extent,
71302 /**
71303 * @param {ol.Feature} feature Feature.
71304 */
71305 function(feature) {
71306 loading = loading ||
71307 this.renderFeature_(feature, resolution, pixelRatio, replayGroup);
71308 }, this);
71309 replayGroup.finish();
71310
71311 if (loading) {
71312 return null;
71313 }
71314
71315 if (this.canvasSize_[0] != size[0] || this.canvasSize_[1] != size[1]) {
71316 this.canvasContext_.canvas.width = size[0];
71317 this.canvasContext_.canvas.height = size[1];
71318 this.canvasSize_[0] = size[0];
71319 this.canvasSize_[1] = size[1];
71320 } else {
71321 this.canvasContext_.clearRect(0, 0, size[0], size[1]);
71322 }
71323
71324 var transform = this.getTransform_(ol.extent.getCenter(extent),
71325 resolution, pixelRatio, size);
71326 replayGroup.replay(this.canvasContext_, pixelRatio, transform, 0, {});
71327
71328 this.replayGroup_ = replayGroup;
71329
71330 return this.canvasContext_.canvas;
71331};
71332
71333
71334/**
71335 * @inheritDoc
71336 */
71337ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
71338 coordinate, resolution, rotation, hitTolerance, skippedFeatureUids, callback) {
71339 if (!this.replayGroup_) {
71340 return undefined;
71341 } else {
71342 /** @type {Object.<string, boolean>} */
71343 var features = {};
71344 return this.replayGroup_.forEachFeatureAtCoordinate(
71345 coordinate, resolution, 0, hitTolerance, skippedFeatureUids,
71346 /**
71347 * @param {ol.Feature|ol.render.Feature} feature Feature.
71348 * @return {?} Callback result.
71349 */
71350 function(feature) {
71351 var key = ol.getUid(feature).toString();
71352 if (!(key in features)) {
71353 features[key] = true;
71354 return callback(feature);
71355 }
71356 });
71357 }
71358};
71359
71360
71361/**
71362 * Get a reference to the wrapped source.
71363 * @return {ol.source.Vector} Source.
71364 * @api
71365 */
71366ol.source.ImageVector.prototype.getSource = function() {
71367 return this.source_;
71368};
71369
71370
71371/**
71372 * Get the style for features. This returns whatever was passed to the `style`
71373 * option at construction or to the `setStyle` method.
71374 * @return {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction}
71375 * Layer style.
71376 * @api
71377 */
71378ol.source.ImageVector.prototype.getStyle = function() {
71379 return this.style_;
71380};
71381
71382
71383/**
71384 * Get the style function.
71385 * @return {ol.StyleFunction|undefined} Layer style function.
71386 * @api
71387 */
71388ol.source.ImageVector.prototype.getStyleFunction = function() {
71389 return this.styleFunction_;
71390};
71391
71392
71393/**
71394 * @param {ol.Coordinate} center Center.
71395 * @param {number} resolution Resolution.
71396 * @param {number} pixelRatio Pixel ratio.
71397 * @param {ol.Size} size Size.
71398 * @return {!ol.Transform} Transform.
71399 * @private
71400 */
71401ol.source.ImageVector.prototype.getTransform_ = function(center, resolution, pixelRatio, size) {
71402 var dx1 = size[0] / 2;
71403 var dy1 = size[1] / 2;
71404 var sx = pixelRatio / resolution;
71405 var sy = -sx;
71406 var dx2 = -center[0];
71407 var dy2 = -center[1];
71408
71409 return ol.transform.compose(this.transform_, dx1, dy1, sx, sy, 0, dx2, dy2);
71410};
71411
71412
71413/**
71414 * Handle changes in image style state.
71415 * @param {ol.events.Event} event Image style change event.
71416 * @private
71417 */
71418ol.source.ImageVector.prototype.handleImageChange_ = function(event) {
71419 this.changed();
71420};
71421
71422
71423/**
71424 * @private
71425 */
71426ol.source.ImageVector.prototype.handleSourceChange_ = function() {
71427 // setState will trigger a CHANGE event, so we always rely
71428 // change events by calling setState.
71429 this.setState(this.source_.getState());
71430};
71431
71432
71433/**
71434 * @param {ol.Feature} feature Feature.
71435 * @param {number} resolution Resolution.
71436 * @param {number} pixelRatio Pixel ratio.
71437 * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
71438 * @return {boolean} `true` if an image is loading.
71439 * @private
71440 */
71441ol.source.ImageVector.prototype.renderFeature_ = function(feature, resolution, pixelRatio, replayGroup) {
71442 var styles;
71443 var styleFunction = feature.getStyleFunction();
71444 if (styleFunction) {
71445 styles = styleFunction.call(feature, resolution);
71446 } else if (this.styleFunction_) {
71447 styles = this.styleFunction_(feature, resolution);
71448 }
71449 if (!styles) {
71450 return false;
71451 }
71452 var i, ii, loading = false;
71453 if (!Array.isArray(styles)) {
71454 styles = [styles];
71455 }
71456 for (i = 0, ii = styles.length; i < ii; ++i) {
71457 loading = ol.renderer.vector.renderFeature(
71458 replayGroup, feature, styles[i],
71459 ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
71460 this.handleImageChange_, this) || loading;
71461 }
71462 return loading;
71463};
71464
71465
71466/**
71467 * Set the style for features. This can be a single style object, an array
71468 * of styles, or a function that takes a feature and resolution and returns
71469 * an array of styles. If it is `undefined` the default style is used. If
71470 * it is `null` the layer has no style (a `null` style), so only features
71471 * that have their own styles will be rendered in the layer. See
71472 * {@link ol.style} for information on the default style.
71473 * @param {ol.style.Style|Array.<ol.style.Style>|ol.StyleFunction|undefined}
71474 * style Layer style.
71475 * @api
71476 */
71477ol.source.ImageVector.prototype.setStyle = function(style) {
71478 this.style_ = style !== undefined ? style : ol.style.Style.defaultFunction;
71479 this.styleFunction_ = !style ?
71480 undefined : ol.style.Style.createFunction(this.style_);
71481 this.changed();
71482};
71483
71484goog.provide('ol.renderer.webgl.ImageLayer');
71485
71486goog.require('ol');
71487goog.require('ol.ViewHint');
71488goog.require('ol.dom');
71489goog.require('ol.extent');
71490goog.require('ol.functions');
71491goog.require('ol.renderer.webgl.Layer');
71492goog.require('ol.source.ImageVector');
71493goog.require('ol.transform');
71494goog.require('ol.webgl');
71495goog.require('ol.webgl.Context');
71496
71497
71498if (ol.ENABLE_WEBGL) {
71499
71500 /**
71501 * @constructor
71502 * @extends {ol.renderer.webgl.Layer}
71503 * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
71504 * @param {ol.layer.Image} imageLayer Tile layer.
71505 */
71506 ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {
71507
71508 ol.renderer.webgl.Layer.call(this, mapRenderer, imageLayer);
71509
71510 /**
71511 * The last rendered image.
71512 * @private
71513 * @type {?ol.ImageBase}
71514 */
71515 this.image_ = null;
71516
71517 /**
71518 * @private
71519 * @type {CanvasRenderingContext2D}
71520 */
71521 this.hitCanvasContext_ = null;
71522
71523 /**
71524 * @private
71525 * @type {?ol.Transform}
71526 */
71527 this.hitTransformationMatrix_ = null;
71528
71529 };
71530 ol.inherits(ol.renderer.webgl.ImageLayer, ol.renderer.webgl.Layer);
71531
71532
71533 /**
71534 * @param {ol.ImageBase} image Image.
71535 * @private
71536 * @return {WebGLTexture} Texture.
71537 */
71538 ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) {
71539
71540 // We meet the conditions to work with non-power of two textures.
71541 // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences#Non-Power_of_Two_Texture_Support
71542 // http://learningwebgl.com/blog/?p=2101
71543
71544 var imageElement = image.getImage();
71545 var gl = this.mapRenderer.getGL();
71546
71547 return ol.webgl.Context.createTexture(
71548 gl, imageElement, ol.webgl.CLAMP_TO_EDGE, ol.webgl.CLAMP_TO_EDGE);
71549 };
71550
71551
71552 /**
71553 * @inheritDoc
71554 */
71555 ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {
71556 var layer = this.getLayer();
71557 var source = layer.getSource();
71558 var resolution = frameState.viewState.resolution;
71559 var rotation = frameState.viewState.rotation;
71560 var skippedFeatureUids = frameState.skippedFeatureUids;
71561 return source.forEachFeatureAtCoordinate(
71562 coordinate, resolution, rotation, hitTolerance, skippedFeatureUids,
71563
71564 /**
71565 * @param {ol.Feature|ol.render.Feature} feature Feature.
71566 * @return {?} Callback result.
71567 */
71568 function(feature) {
71569 return callback.call(thisArg, feature, layer);
71570 });
71571 };
71572
71573
71574 /**
71575 * @inheritDoc
71576 */
71577 ol.renderer.webgl.ImageLayer.prototype.prepareFrame = function(frameState, layerState, context) {
71578
71579 var gl = this.mapRenderer.getGL();
71580
71581 var pixelRatio = frameState.pixelRatio;
71582 var viewState = frameState.viewState;
71583 var viewCenter = viewState.center;
71584 var viewResolution = viewState.resolution;
71585 var viewRotation = viewState.rotation;
71586
71587 var image = this.image_;
71588 var texture = this.texture;
71589 var imageLayer = /** @type {ol.layer.Image} */ (this.getLayer());
71590 var imageSource = imageLayer.getSource();
71591
71592 var hints = frameState.viewHints;
71593
71594 var renderedExtent = frameState.extent;
71595 if (layerState.extent !== undefined) {
71596 renderedExtent = ol.extent.getIntersection(
71597 renderedExtent, layerState.extent);
71598 }
71599 if (!hints[ol.ViewHint.ANIMATING] && !hints[ol.ViewHint.INTERACTING] &&
71600 !ol.extent.isEmpty(renderedExtent)) {
71601 var projection = viewState.projection;
71602 if (!ol.ENABLE_RASTER_REPROJECTION) {
71603 var sourceProjection = imageSource.getProjection();
71604 if (sourceProjection) {
71605 projection = sourceProjection;
71606 }
71607 }
71608 var image_ = imageSource.getImage(renderedExtent, viewResolution,
71609 pixelRatio, projection);
71610 if (image_) {
71611 var loaded = this.loadImage(image_);
71612 if (loaded) {
71613 image = image_;
71614 texture = this.createTexture_(image_);
71615 if (this.texture) {
71616 /**
71617 * @param {WebGLRenderingContext} gl GL.
71618 * @param {WebGLTexture} texture Texture.
71619 */
71620 var postRenderFunction = function(gl, texture) {
71621 if (!gl.isContextLost()) {
71622 gl.deleteTexture(texture);
71623 }
71624 }.bind(null, gl, this.texture);
71625 frameState.postRenderFunctions.push(
71626 /** @type {ol.PostRenderFunction} */ (postRenderFunction)
71627 );
71628 }
71629 }
71630 }
71631 }
71632
71633 if (image) {
71634 var canvas = this.mapRenderer.getContext().getCanvas();
71635
71636 this.updateProjectionMatrix_(canvas.width, canvas.height,
71637 pixelRatio, viewCenter, viewResolution, viewRotation,
71638 image.getExtent());
71639 this.hitTransformationMatrix_ = null;
71640
71641 // Translate and scale to flip the Y coord.
71642 var texCoordMatrix = this.texCoordMatrix;
71643 ol.transform.reset(texCoordMatrix);
71644 ol.transform.scale(texCoordMatrix, 1, -1);
71645 ol.transform.translate(texCoordMatrix, 0, -1);
71646
71647 this.image_ = image;
71648 this.texture = texture;
71649
71650 this.updateAttributions(frameState.attributions, image.getAttributions());
71651 this.updateLogos(frameState, imageSource);
71652 }
71653
71654 return !!image;
71655 };
71656
71657
71658 /**
71659 * @param {number} canvasWidth Canvas width.
71660 * @param {number} canvasHeight Canvas height.
71661 * @param {number} pixelRatio Pixel ratio.
71662 * @param {ol.Coordinate} viewCenter View center.
71663 * @param {number} viewResolution View resolution.
71664 * @param {number} viewRotation View rotation.
71665 * @param {ol.Extent} imageExtent Image extent.
71666 * @private
71667 */
71668 ol.renderer.webgl.ImageLayer.prototype.updateProjectionMatrix_ = function(canvasWidth, canvasHeight, pixelRatio,
71669 viewCenter, viewResolution, viewRotation, imageExtent) {
71670
71671 var canvasExtentWidth = canvasWidth * viewResolution;
71672 var canvasExtentHeight = canvasHeight * viewResolution;
71673
71674 var projectionMatrix = this.projectionMatrix;
71675 ol.transform.reset(projectionMatrix);
71676 ol.transform.scale(projectionMatrix,
71677 pixelRatio * 2 / canvasExtentWidth,
71678 pixelRatio * 2 / canvasExtentHeight);
71679 ol.transform.rotate(projectionMatrix, -viewRotation);
71680 ol.transform.translate(projectionMatrix,
71681 imageExtent[0] - viewCenter[0],
71682 imageExtent[1] - viewCenter[1]);
71683 ol.transform.scale(projectionMatrix,
71684 (imageExtent[2] - imageExtent[0]) / 2,
71685 (imageExtent[3] - imageExtent[1]) / 2);
71686 ol.transform.translate(projectionMatrix, 1, 1);
71687
71688 };
71689
71690
71691 /**
71692 * @inheritDoc
71693 */
71694 ol.renderer.webgl.ImageLayer.prototype.hasFeatureAtCoordinate = function(coordinate, frameState) {
71695 var hasFeature = this.forEachFeatureAtCoordinate(
71696 coordinate, frameState, 0, ol.functions.TRUE, this);
71697 return hasFeature !== undefined;
71698 };
71699
71700
71701 /**
71702 * @inheritDoc
71703 */
71704 ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
71705 if (!this.image_ || !this.image_.getImage()) {
71706 return undefined;
71707 }
71708
71709 if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
71710 // for ImageVector sources use the original hit-detection logic,
71711 // so that for example also transparent polygons are detected
71712 var coordinate = ol.transform.apply(
71713 frameState.pixelToCoordinateTransform, pixel.slice());
71714 var hasFeature = this.forEachFeatureAtCoordinate(
71715 coordinate, frameState, 0, ol.functions.TRUE, this);
71716
71717 if (hasFeature) {
71718 return callback.call(thisArg, this.getLayer(), null);
71719 } else {
71720 return undefined;
71721 }
71722 } else {
71723 var imageSize =
71724 [this.image_.getImage().width, this.image_.getImage().height];
71725
71726 if (!this.hitTransformationMatrix_) {
71727 this.hitTransformationMatrix_ = this.getHitTransformationMatrix_(
71728 frameState.size, imageSize);
71729 }
71730
71731 var pixelOnFrameBuffer = ol.transform.apply(
71732 this.hitTransformationMatrix_, pixel.slice());
71733
71734 if (pixelOnFrameBuffer[0] < 0 || pixelOnFrameBuffer[0] > imageSize[0] ||
71735 pixelOnFrameBuffer[1] < 0 || pixelOnFrameBuffer[1] > imageSize[1]) {
71736 // outside the image, no need to check
71737 return undefined;
71738 }
71739
71740 if (!this.hitCanvasContext_) {
71741 this.hitCanvasContext_ = ol.dom.createCanvasContext2D(1, 1);
71742 }
71743
71744 this.hitCanvasContext_.clearRect(0, 0, 1, 1);
71745 this.hitCanvasContext_.drawImage(this.image_.getImage(),
71746 pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 0, 0, 1, 1);
71747
71748 var imageData = this.hitCanvasContext_.getImageData(0, 0, 1, 1).data;
71749 if (imageData[3] > 0) {
71750 return callback.call(thisArg, this.getLayer(), imageData);
71751 } else {
71752 return undefined;
71753 }
71754 }
71755 };
71756
71757
71758 /**
71759 * The transformation matrix to get the pixel on the image for a
71760 * pixel on the map.
71761 * @param {ol.Size} mapSize The map size.
71762 * @param {ol.Size} imageSize The image size.
71763 * @return {ol.Transform} The transformation matrix.
71764 * @private
71765 */
71766 ol.renderer.webgl.ImageLayer.prototype.getHitTransformationMatrix_ = function(mapSize, imageSize) {
71767 // the first matrix takes a map pixel, flips the y-axis and scales to
71768 // a range between -1 ... 1
71769 var mapCoordTransform = ol.transform.create();
71770 ol.transform.translate(mapCoordTransform, -1, -1);
71771 ol.transform.scale(mapCoordTransform, 2 / mapSize[0], 2 / mapSize[1]);
71772 ol.transform.translate(mapCoordTransform, 0, mapSize[1]);
71773 ol.transform.scale(mapCoordTransform, 1, -1);
71774
71775 // the second matrix is the inverse of the projection matrix used in the
71776 // shader for drawing
71777 var projectionMatrixInv = ol.transform.invert(this.projectionMatrix.slice());
71778
71779 // the third matrix scales to the image dimensions and flips the y-axis again
71780 var transform = ol.transform.create();
71781 ol.transform.translate(transform, 0, imageSize[1]);
71782 ol.transform.scale(transform, 1, -1);
71783 ol.transform.scale(transform, imageSize[0] / 2, imageSize[1] / 2);
71784 ol.transform.translate(transform, 1, 1);
71785
71786 ol.transform.multiply(transform, projectionMatrixInv);
71787 ol.transform.multiply(transform, mapCoordTransform);
71788
71789 return transform;
71790 };
71791
71792}
71793
71794goog.provide('ol.layer.Image');
71795
71796goog.require('ol');
71797goog.require('ol.layer.Layer');
71798goog.require('ol.renderer.Type');
71799goog.require('ol.renderer.canvas.ImageLayer');
71800goog.require('ol.renderer.webgl.ImageLayer');
71801
71802
71803/**
71804 * @classdesc
71805 * Server-rendered images that are available for arbitrary extents and
71806 * resolutions.
71807 * Note that any property set in the options is set as a {@link ol.Object}
71808 * property on the layer object; for example, setting `title: 'My Title'` in the
71809 * options means that `title` is observable, and has get/set accessors.
71810 *
71811 * @constructor
71812 * @extends {ol.layer.Layer}
71813 * @fires ol.render.Event
71814 * @param {olx.layer.ImageOptions=} opt_options Layer options.
71815 * @api
71816 */
71817ol.layer.Image = function(opt_options) {
71818 var options = opt_options ? opt_options : {};
71819 ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (options));
71820};
71821ol.inherits(ol.layer.Image, ol.layer.Layer);
71822
71823
71824/**
71825 * @inheritDoc
71826 */
71827ol.layer.Image.prototype.createRenderer = function(mapRenderer) {
71828 var renderer = null;
71829 var type = mapRenderer.getType();
71830 if (ol.ENABLE_CANVAS && type === ol.renderer.Type.CANVAS) {
71831 renderer = new ol.renderer.canvas.ImageLayer(this);
71832 } else if (ol.ENABLE_WEBGL && type === ol.renderer.Type.WEBGL) {
71833 renderer = new ol.renderer.webgl.ImageLayer(/** @type {ol.renderer.webgl.Map} */ (mapRenderer), this);
71834 }
71835 return renderer;
71836};
71837
71838
71839/**
71840 * Return the associated {@link ol.source.Image source} of the image layer.
71841 * @function
71842 * @return {ol.source.Image} Source.
71843 * @api
71844 */
71845ol.layer.Image.prototype.getSource;
71846
71847goog.provide('ol.layer.TileProperty');
71848
71849/**
71850 * @enum {string}
71851 */
71852ol.layer.TileProperty = {
71853 PRELOAD: 'preload',
71854 USE_INTERIM_TILES_ON_ERROR: 'useInterimTilesOnError'
71855};
71856
71857// FIXME find correct globalCompositeOperation
71858
71859goog.provide('ol.renderer.canvas.TileLayer');
71860
71861goog.require('ol');
71862goog.require('ol.TileRange');
71863goog.require('ol.TileState');
71864goog.require('ol.ViewHint');
71865goog.require('ol.array');
71866goog.require('ol.dom');
71867goog.require('ol.extent');
71868goog.require('ol.renderer.canvas.IntermediateCanvas');
71869goog.require('ol.transform');
71870
71871
71872/**
71873 * @constructor
71874 * @extends {ol.renderer.canvas.IntermediateCanvas}
71875 * @param {ol.layer.Tile|ol.layer.VectorTile} tileLayer Tile layer.
71876 */
71877ol.renderer.canvas.TileLayer = function(tileLayer) {
71878
71879 ol.renderer.canvas.IntermediateCanvas.call(this, tileLayer);
71880
71881 /**
71882 * @protected
71883 * @type {CanvasRenderingContext2D}
71884 */
71885 this.context = this.context === null ? null : ol.dom.createCanvasContext2D();
71886
71887 /**
71888 * @private
71889 * @type {number}
71890 */
71891 this.oversampling_;
71892
71893 /**
71894 * @private
71895 * @type {ol.Extent}
71896 */
71897 this.renderedExtent_ = null;
71898
71899 /**
71900 * @protected
71901 * @type {number}
71902 */
71903 this.renderedRevision;
71904
71905 /**
71906 * @protected
71907 * @type {!Array.<ol.Tile>}
71908 */
71909 this.renderedTiles = [];
71910
71911 /**
71912 * @protected
71913 * @type {ol.Extent}
71914 */
71915 this.tmpExtent = ol.extent.createEmpty();
71916
71917 /**
71918 * @private
71919 * @type {ol.TileRange}
71920 */
71921 this.tmpTileRange_ = new ol.TileRange(0, 0, 0, 0);
71922
71923 /**
71924 * @private
71925 * @type {ol.Transform}
71926 */
71927 this.imageTransform_ = ol.transform.create();
71928
71929 /**
71930 * @protected
71931 * @type {number}
71932 */
71933 this.zDirection = 0;
71934
71935};
71936ol.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.IntermediateCanvas);
71937
71938
71939/**
71940 * @private
71941 * @param {ol.Tile} tile Tile.
71942 * @return {boolean} Tile is drawable.
71943 */
71944ol.renderer.canvas.TileLayer.prototype.isDrawableTile_ = function(tile) {
71945 var tileState = tile.getState();
71946 var useInterimTilesOnError = this.getLayer().getUseInterimTilesOnError();
71947 return tileState == ol.TileState.LOADED ||
71948 tileState == ol.TileState.EMPTY ||
71949 tileState == ol.TileState.ERROR && !useInterimTilesOnError;
71950};
71951
71952/**
71953 * @inheritDoc
71954 */
71955ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(frameState, layerState) {
71956
71957 var pixelRatio = frameState.pixelRatio;
71958 var size = frameState.size;
71959 var viewState = frameState.viewState;
71960 var projection = viewState.projection;
71961 var viewResolution = viewState.resolution;
71962 var viewCenter = viewState.center;
71963
71964 var tileLayer = this.getLayer();
71965 var tileSource = /** @type {ol.source.Tile} */ (tileLayer.getSource());
71966 var sourceRevision = tileSource.getRevision();
71967 var tileGrid = tileSource.getTileGridForProjection(projection);
71968 var z = tileGrid.getZForResolution(viewResolution, this.zDirection);
71969 var tileResolution = tileGrid.getResolution(z);
71970 var oversampling = Math.round(viewResolution / tileResolution) || 1;
71971 var extent = frameState.extent;
71972
71973 if (layerState.extent !== undefined) {
71974 extent = ol.extent.getIntersection(extent, layerState.extent);
71975 }
71976 if (ol.extent.isEmpty(extent)) {
71977 // Return false to prevent the rendering of the layer.
71978 return false;
71979 }
71980
71981 var tileRange = tileGrid.getTileRangeForExtentAndResolution(
71982 extent, tileResolution);
71983 var imageExtent = tileGrid.getTileRangeExtent(z, tileRange);
71984
71985 var tilePixelRatio = tileSource.getTilePixelRatio(pixelRatio);
71986
71987 /**
71988 * @type {Object.<number, Object.<string, ol.Tile>>}
71989 */
71990 var tilesToDrawByZ = {};
71991 tilesToDrawByZ[z] = {};
71992
71993 var findLoadedTiles = this.createLoadedTileFinder(
71994 tileSource, projection, tilesToDrawByZ);
71995
71996 var tmpExtent = this.tmpExtent;
71997 var tmpTileRange = this.tmpTileRange_;
71998 var newTiles = false;
71999 var tile, x, y;
72000 for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
72001 for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
72002 tile = tileSource.getTile(z, x, y, pixelRatio, projection);
72003 if (tile.getState() == ol.TileState.ERROR) {
72004 if (!tileLayer.getUseInterimTilesOnError()) {
72005 // When useInterimTilesOnError is false, we consider the error tile as loaded.
72006 tile.setState(ol.TileState.LOADED);
72007 } else if (tileLayer.getPreload() > 0) {
72008 // Preloaded tiles for lower resolutions might have finished loading.
72009 newTiles = true;
72010 }
72011 }
72012 if (!this.isDrawableTile_(tile)) {
72013 tile = tile.getInterimTile();
72014 }
72015 if (this.isDrawableTile_(tile)) {
72016 if (tile.getState() == ol.TileState.LOADED) {
72017 tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
72018 if (!newTiles && this.renderedTiles.indexOf(tile) == -1) {
72019 newTiles = true;
72020 }
72021 }
72022 continue;
72023 }
72024
72025 var fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
72026 tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
72027 if (!fullyLoaded) {
72028 var childTileRange = tileGrid.getTileCoordChildTileRange(
72029 tile.tileCoord, tmpTileRange, tmpExtent);
72030 if (childTileRange) {
72031 findLoadedTiles(z + 1, childTileRange);
72032 }
72033 }
72034
72035 }
72036 }
72037
72038 var renderedResolution = tileResolution * pixelRatio / tilePixelRatio * oversampling;
72039 var hints = frameState.viewHints;
72040 var animatingOrInteracting = hints[ol.ViewHint.ANIMATING] || hints[ol.ViewHint.INTERACTING];
72041 if (!(this.renderedResolution && Date.now() - frameState.time > 16 && animatingOrInteracting) && (
72042 newTiles ||
72043 !(this.renderedExtent_ && ol.extent.containsExtent(this.renderedExtent_, extent)) ||
72044 this.renderedRevision != sourceRevision ||
72045 oversampling != this.oversampling_ ||
72046 !animatingOrInteracting && renderedResolution != this.renderedResolution
72047 )) {
72048
72049 var context = this.context;
72050 if (context) {
72051 var tilePixelSize = tileSource.getTilePixelSize(z, pixelRatio, projection);
72052 var width = Math.round(tileRange.getWidth() * tilePixelSize[0] / oversampling);
72053 var height = Math.round(tileRange.getHeight() * tilePixelSize[1] / oversampling);
72054 var canvas = context.canvas;
72055 if (canvas.width != width || canvas.height != height) {
72056 this.oversampling_ = oversampling;
72057 canvas.width = width;
72058 canvas.height = height;
72059 } else {
72060 context.clearRect(0, 0, width, height);
72061 oversampling = this.oversampling_;
72062 }
72063 }
72064
72065 this.renderedTiles.length = 0;
72066 /** @type {Array.<number>} */
72067 var zs = Object.keys(tilesToDrawByZ).map(Number);
72068 zs.sort(ol.array.numberSafeCompareFunction);
72069 var currentResolution, currentScale, currentTilePixelSize, currentZ, i, ii;
72070 var tileExtent, tileGutter, tilesToDraw, w, h;
72071 for (i = 0, ii = zs.length; i < ii; ++i) {
72072 currentZ = zs[i];
72073 currentTilePixelSize = tileSource.getTilePixelSize(currentZ, pixelRatio, projection);
72074 currentResolution = tileGrid.getResolution(currentZ);
72075 currentScale = currentResolution / tileResolution;
72076 tileGutter = tilePixelRatio * tileSource.getGutter(projection);
72077 tilesToDraw = tilesToDrawByZ[currentZ];
72078 for (var tileCoordKey in tilesToDraw) {
72079 tile = tilesToDraw[tileCoordKey];
72080 tileExtent = tileGrid.getTileCoordExtent(tile.getTileCoord(), tmpExtent);
72081 x = (tileExtent[0] - imageExtent[0]) / tileResolution * tilePixelRatio / oversampling;
72082 y = (imageExtent[3] - tileExtent[3]) / tileResolution * tilePixelRatio / oversampling;
72083 w = currentTilePixelSize[0] * currentScale / oversampling;
72084 h = currentTilePixelSize[1] * currentScale / oversampling;
72085 this.drawTileImage(tile, frameState, layerState, x, y, w, h, tileGutter);
72086 this.renderedTiles.push(tile);
72087 }
72088 }
72089
72090 this.renderedRevision = sourceRevision;
72091 this.renderedResolution = tileResolution * pixelRatio / tilePixelRatio * oversampling;
72092 this.renderedExtent_ = imageExtent;
72093 }
72094
72095 var scale = this.renderedResolution / viewResolution;
72096 var transform = ol.transform.compose(this.imageTransform_,
72097 pixelRatio * size[0] / 2, pixelRatio * size[1] / 2,
72098 scale, scale,
72099 0,
72100 (this.renderedExtent_[0] - viewCenter[0]) / this.renderedResolution * pixelRatio,
72101 (viewCenter[1] - this.renderedExtent_[3]) / this.renderedResolution * pixelRatio);
72102 ol.transform.compose(this.coordinateToCanvasPixelTransform,
72103 pixelRatio * size[0] / 2 - transform[4], pixelRatio * size[1] / 2 - transform[5],
72104 pixelRatio / viewResolution, -pixelRatio / viewResolution,
72105 0,
72106 -viewCenter[0], -viewCenter[1]);
72107
72108
72109 this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
72110 this.manageTilePyramid(frameState, tileSource, tileGrid, pixelRatio,
72111 projection, extent, z, tileLayer.getPreload());
72112 this.scheduleExpireCache(frameState, tileSource);
72113 this.updateLogos(frameState, tileSource);
72114
72115 return this.renderedTiles.length > 0;
72116};
72117
72118
72119/**
72120 * @param {ol.Tile} tile Tile.
72121 * @param {olx.FrameState} frameState Frame state.
72122 * @param {ol.LayerState} layerState Layer state.
72123 * @param {number} x Left of the tile.
72124 * @param {number} y Top of the tile.
72125 * @param {number} w Width of the tile.
72126 * @param {number} h Height of the tile.
72127 * @param {number} gutter Tile gutter.
72128 */
72129ol.renderer.canvas.TileLayer.prototype.drawTileImage = function(tile, frameState, layerState, x, y, w, h, gutter) {
72130 if (!this.getLayer().getSource().getOpaque(frameState.viewState.projection)) {
72131 this.context.clearRect(x, y, w, h);
72132 }
72133 var image = tile.getImage(this.getLayer());
72134 if (image) {
72135 this.context.drawImage(image, gutter, gutter,
72136 image.width - 2 * gutter, image.height - 2 * gutter, x, y, w, h);
72137 }
72138};
72139
72140
72141/**
72142 * @inheritDoc
72143 */
72144ol.renderer.canvas.TileLayer.prototype.getImage = function() {
72145 var context = this.context;
72146 return context ? context.canvas : null;
72147};
72148
72149
72150/**
72151 * @function
72152 * @return {ol.layer.Tile|ol.layer.VectorTile}
72153 */
72154ol.renderer.canvas.TileLayer.prototype.getLayer;
72155
72156
72157/**
72158 * @inheritDoc
72159 */
72160ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() {
72161 return this.imageTransform_;
72162};
72163
72164// This file is automatically generated, do not edit
72165/* eslint openlayers-internal/no-missing-requires: 0 */
72166goog.provide('ol.renderer.webgl.tilelayershader');
72167
72168goog.require('ol');
72169goog.require('ol.webgl.Fragment');
72170goog.require('ol.webgl.Vertex');
72171
72172if (ol.ENABLE_WEBGL) {
72173
72174 /**
72175 * @constructor
72176 * @extends {ol.webgl.Fragment}
72177 * @struct
72178 */
72179 ol.renderer.webgl.tilelayershader.Fragment = function() {
72180 ol.webgl.Fragment.call(this, ol.renderer.webgl.tilelayershader.Fragment.SOURCE);
72181 };
72182 ol.inherits(ol.renderer.webgl.tilelayershader.Fragment, ol.webgl.Fragment);
72183
72184
72185 /**
72186 * @const
72187 * @type {string}
72188 */
72189 ol.renderer.webgl.tilelayershader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_texCoord;\n\n\nuniform sampler2D u_texture;\n\nvoid main(void) {\n gl_FragColor = texture2D(u_texture, v_texCoord);\n}\n';
72190
72191
72192 /**
72193 * @const
72194 * @type {string}
72195 */
72196 ol.renderer.webgl.tilelayershader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;uniform sampler2D e;void main(void){gl_FragColor=texture2D(e,a);}';
72197
72198
72199 /**
72200 * @const
72201 * @type {string}
72202 */
72203 ol.renderer.webgl.tilelayershader.Fragment.SOURCE = ol.DEBUG_WEBGL ?
72204 ol.renderer.webgl.tilelayershader.Fragment.DEBUG_SOURCE :
72205 ol.renderer.webgl.tilelayershader.Fragment.OPTIMIZED_SOURCE;
72206
72207
72208 ol.renderer.webgl.tilelayershader.fragment = new ol.renderer.webgl.tilelayershader.Fragment();
72209
72210
72211 /**
72212 * @constructor
72213 * @extends {ol.webgl.Vertex}
72214 * @struct
72215 */
72216 ol.renderer.webgl.tilelayershader.Vertex = function() {
72217 ol.webgl.Vertex.call(this, ol.renderer.webgl.tilelayershader.Vertex.SOURCE);
72218 };
72219 ol.inherits(ol.renderer.webgl.tilelayershader.Vertex, ol.webgl.Vertex);
72220
72221
72222 /**
72223 * @const
72224 * @type {string}
72225 */
72226 ol.renderer.webgl.tilelayershader.Vertex.DEBUG_SOURCE = 'varying vec2 v_texCoord;\n\n\nattribute vec2 a_position;\nattribute vec2 a_texCoord;\nuniform vec4 u_tileOffset;\n\nvoid main(void) {\n gl_Position = vec4(a_position * u_tileOffset.xy + u_tileOffset.zw, 0., 1.);\n v_texCoord = a_texCoord;\n}\n\n\n';
72227
72228
72229 /**
72230 * @const
72231 * @type {string}
72232 */
72233 ol.renderer.webgl.tilelayershader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;attribute vec2 b;attribute vec2 c;uniform vec4 d;void main(void){gl_Position=vec4(b*d.xy+d.zw,0.,1.);a=c;}';
72234
72235
72236 /**
72237 * @const
72238 * @type {string}
72239 */
72240 ol.renderer.webgl.tilelayershader.Vertex.SOURCE = ol.DEBUG_WEBGL ?
72241 ol.renderer.webgl.tilelayershader.Vertex.DEBUG_SOURCE :
72242 ol.renderer.webgl.tilelayershader.Vertex.OPTIMIZED_SOURCE;
72243
72244
72245 ol.renderer.webgl.tilelayershader.vertex = new ol.renderer.webgl.tilelayershader.Vertex();
72246
72247
72248 /**
72249 * @constructor
72250 * @param {WebGLRenderingContext} gl GL.
72251 * @param {WebGLProgram} program Program.
72252 * @struct
72253 */
72254 ol.renderer.webgl.tilelayershader.Locations = function(gl, program) {
72255
72256 /**
72257 * @type {WebGLUniformLocation}
72258 */
72259 this.u_texture = gl.getUniformLocation(
72260 program, ol.DEBUG_WEBGL ? 'u_texture' : 'e');
72261
72262 /**
72263 * @type {WebGLUniformLocation}
72264 */
72265 this.u_tileOffset = gl.getUniformLocation(
72266 program, ol.DEBUG_WEBGL ? 'u_tileOffset' : 'd');
72267
72268 /**
72269 * @type {number}
72270 */
72271 this.a_position = gl.getAttribLocation(
72272 program, ol.DEBUG_WEBGL ? 'a_position' : 'b');
72273
72274 /**
72275 * @type {number}
72276 */
72277 this.a_texCoord = gl.getAttribLocation(
72278 program, ol.DEBUG_WEBGL ? 'a_texCoord' : 'c');
72279 };
72280
72281}
72282
72283// FIXME large resolutions lead to too large framebuffers :-(
72284// FIXME animated shaders! check in redraw
72285
72286goog.provide('ol.renderer.webgl.TileLayer');
72287
72288goog.require('ol');
72289goog.require('ol.TileState');
72290goog.require('ol.TileRange');
72291goog.require('ol.array');
72292goog.require('ol.extent');
72293goog.require('ol.math');
72294goog.require('ol.renderer.webgl.Layer');
72295goog.require('ol.renderer.webgl.tilelayershader');
72296goog.require('ol.size');
72297goog.require('ol.transform');
72298goog.require('ol.webgl');
72299goog.require('ol.webgl.Buffer');
72300
72301
72302if (ol.ENABLE_WEBGL) {
72303
72304 /**
72305 * @constructor
72306 * @extends {ol.renderer.webgl.Layer}
72307 * @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
72308 * @param {ol.layer.Tile} tileLayer Tile layer.
72309 */
72310 ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
72311
72312 ol.renderer.webgl.Layer.call(this, mapRenderer, tileLayer);
72313
72314 /**
72315 * @private
72316 * @type {ol.webgl.Fragment}
72317 */
72318 this.fragmentShader_ = ol.renderer.webgl.tilelayershader.fragment;
72319
72320 /**
72321 * @private
72322 * @type {ol.webgl.Vertex}
72323 */
72324 this.vertexShader_ = ol.renderer.webgl.tilelayershader.vertex;
72325
72326 /**
72327 * @private
72328 * @type {ol.renderer.webgl.tilelayershader.Locations}
72329 */
72330 this.locations_ = null;
72331
72332 /**
72333 * @private
72334 * @type {ol.webgl.Buffer}
72335 */
72336 this.renderArrayBuffer_ = new ol.webgl.Buffer([
72337 0, 0, 0, 1,
72338 1, 0, 1, 1,
72339 0, 1, 0, 0,
72340 1, 1, 1, 0
72341 ]);
72342
72343 /**
72344 * @private
72345 * @type {ol.TileRange}
72346 */
72347 this.renderedTileRange_ = null;
72348
72349 /**
72350 * @private
72351 * @type {ol.Extent}
72352 */
72353 this.renderedFramebufferExtent_ = null;
72354
72355 /**
72356 * @private
72357 * @type {number}
72358 */
72359 this.renderedRevision_ = -1;
72360
72361 /**
72362 * @private
72363 * @type {ol.Size}
72364 */
72365 this.tmpSize_ = [0, 0];
72366
72367 };
72368 ol.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);
72369
72370
72371 /**
72372 * @inheritDoc
72373 */
72374 ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
72375 var context = this.mapRenderer.getContext();
72376 context.deleteBuffer(this.renderArrayBuffer_);
72377 ol.renderer.webgl.Layer.prototype.disposeInternal.call(this);
72378 };
72379
72380
72381 /**
72382 * @inheritDoc
72383 */
72384 ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder = function(source, projection, tiles) {
72385 var mapRenderer = this.mapRenderer;
72386
72387 return (
72388 /**
72389 * @param {number} zoom Zoom level.
72390 * @param {ol.TileRange} tileRange Tile range.
72391 * @return {boolean} The tile range is fully loaded.
72392 */
72393 function(zoom, tileRange) {
72394 function callback(tile) {
72395 var loaded = mapRenderer.isTileTextureLoaded(tile);
72396 if (loaded) {
72397 if (!tiles[zoom]) {
72398 tiles[zoom] = {};
72399 }
72400 tiles[zoom][tile.tileCoord.toString()] = tile;
72401 }
72402 return loaded;
72403 }
72404 return source.forEachLoadedTile(projection, zoom, tileRange, callback);
72405 });
72406 };
72407
72408
72409 /**
72410 * @inheritDoc
72411 */
72412 ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {
72413 ol.renderer.webgl.Layer.prototype.handleWebGLContextLost.call(this);
72414 this.locations_ = null;
72415 };
72416
72417
72418 /**
72419 * @inheritDoc
72420 */
72421 ol.renderer.webgl.TileLayer.prototype.prepareFrame = function(frameState, layerState, context) {
72422
72423 var mapRenderer = this.mapRenderer;
72424 var gl = context.getGL();
72425
72426 var viewState = frameState.viewState;
72427 var projection = viewState.projection;
72428
72429 var tileLayer = /** @type {ol.layer.Tile} */ (this.getLayer());
72430 var tileSource = tileLayer.getSource();
72431 var tileGrid = tileSource.getTileGridForProjection(projection);
72432 var z = tileGrid.getZForResolution(viewState.resolution);
72433 var tileResolution = tileGrid.getResolution(z);
72434
72435 var tilePixelSize =
72436 tileSource.getTilePixelSize(z, frameState.pixelRatio, projection);
72437 var pixelRatio = tilePixelSize[0] /
72438 ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize_)[0];
72439 var tilePixelResolution = tileResolution / pixelRatio;
72440 var tileGutter = tileSource.getTilePixelRatio(pixelRatio) * tileSource.getGutter(projection);
72441
72442 var center = viewState.center;
72443 var extent = frameState.extent;
72444 var tileRange = tileGrid.getTileRangeForExtentAndResolution(
72445 extent, tileResolution);
72446
72447 var framebufferExtent;
72448 if (this.renderedTileRange_ &&
72449 this.renderedTileRange_.equals(tileRange) &&
72450 this.renderedRevision_ == tileSource.getRevision()) {
72451 framebufferExtent = this.renderedFramebufferExtent_;
72452 } else {
72453
72454 var tileRangeSize = tileRange.getSize();
72455
72456 var maxDimension = Math.max(
72457 tileRangeSize[0] * tilePixelSize[0],
72458 tileRangeSize[1] * tilePixelSize[1]);
72459 var framebufferDimension = ol.math.roundUpToPowerOfTwo(maxDimension);
72460 var framebufferExtentDimension = tilePixelResolution * framebufferDimension;
72461 var origin = tileGrid.getOrigin(z);
72462 var minX = origin[0] +
72463 tileRange.minX * tilePixelSize[0] * tilePixelResolution;
72464 var minY = origin[1] +
72465 tileRange.minY * tilePixelSize[1] * tilePixelResolution;
72466 framebufferExtent = [
72467 minX, minY,
72468 minX + framebufferExtentDimension, minY + framebufferExtentDimension
72469 ];
72470
72471 this.bindFramebuffer(frameState, framebufferDimension);
72472 gl.viewport(0, 0, framebufferDimension, framebufferDimension);
72473
72474 gl.clearColor(0, 0, 0, 0);
72475 gl.clear(ol.webgl.COLOR_BUFFER_BIT);
72476 gl.disable(ol.webgl.BLEND);
72477
72478 var program = context.getProgram(this.fragmentShader_, this.vertexShader_);
72479 context.useProgram(program);
72480 if (!this.locations_) {
72481 // eslint-disable-next-line openlayers-internal/no-missing-requires
72482 this.locations_ = new ol.renderer.webgl.tilelayershader.Locations(gl, program);
72483 }
72484
72485 context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.renderArrayBuffer_);
72486 gl.enableVertexAttribArray(this.locations_.a_position);
72487 gl.vertexAttribPointer(
72488 this.locations_.a_position, 2, ol.webgl.FLOAT, false, 16, 0);
72489 gl.enableVertexAttribArray(this.locations_.a_texCoord);
72490 gl.vertexAttribPointer(
72491 this.locations_.a_texCoord, 2, ol.webgl.FLOAT, false, 16, 8);
72492 gl.uniform1i(this.locations_.u_texture, 0);
72493
72494 /**
72495 * @type {Object.<number, Object.<string, ol.Tile>>}
72496 */
72497 var tilesToDrawByZ = {};
72498 tilesToDrawByZ[z] = {};
72499
72500 var findLoadedTiles = this.createLoadedTileFinder(
72501 tileSource, projection, tilesToDrawByZ);
72502
72503 var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
72504 var allTilesLoaded = true;
72505 var tmpExtent = ol.extent.createEmpty();
72506 var tmpTileRange = new ol.TileRange(0, 0, 0, 0);
72507 var childTileRange, drawable, fullyLoaded, tile, tileState;
72508 var x, y, tileExtent;
72509 for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
72510 for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
72511
72512 tile = tileSource.getTile(z, x, y, pixelRatio, projection);
72513 if (layerState.extent !== undefined) {
72514 // ignore tiles outside layer extent
72515 tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);
72516 if (!ol.extent.intersects(tileExtent, layerState.extent)) {
72517 continue;
72518 }
72519 }
72520 tileState = tile.getState();
72521 drawable = tileState == ol.TileState.LOADED ||
72522 tileState == ol.TileState.EMPTY ||
72523 tileState == ol.TileState.ERROR && !useInterimTilesOnError;
72524 if (!drawable) {
72525 tile = tile.getInterimTile();
72526 }
72527 tileState = tile.getState();
72528 if (tileState == ol.TileState.LOADED) {
72529 if (mapRenderer.isTileTextureLoaded(tile)) {
72530 tilesToDrawByZ[z][tile.tileCoord.toString()] = tile;
72531 continue;
72532 }
72533 } else if (tileState == ol.TileState.EMPTY ||
72534 (tileState == ol.TileState.ERROR &&
72535 !useInterimTilesOnError)) {
72536 continue;
72537 }
72538
72539 allTilesLoaded = false;
72540 fullyLoaded = tileGrid.forEachTileCoordParentTileRange(
72541 tile.tileCoord, findLoadedTiles, null, tmpTileRange, tmpExtent);
72542 if (!fullyLoaded) {
72543 childTileRange = tileGrid.getTileCoordChildTileRange(
72544 tile.tileCoord, tmpTileRange, tmpExtent);
72545 if (childTileRange) {
72546 findLoadedTiles(z + 1, childTileRange);
72547 }
72548 }
72549
72550 }
72551
72552 }
72553
72554 /** @type {Array.<number>} */
72555 var zs = Object.keys(tilesToDrawByZ).map(Number);
72556 zs.sort(ol.array.numberSafeCompareFunction);
72557 var u_tileOffset = new Float32Array(4);
72558 var i, ii, tileKey, tilesToDraw;
72559 for (i = 0, ii = zs.length; i < ii; ++i) {
72560 tilesToDraw = tilesToDrawByZ[zs[i]];
72561 for (tileKey in tilesToDraw) {
72562 tile = tilesToDraw[tileKey];
72563 tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord, tmpExtent);
72564 u_tileOffset[0] = 2 * (tileExtent[2] - tileExtent[0]) /
72565 framebufferExtentDimension;
72566 u_tileOffset[1] = 2 * (tileExtent[3] - tileExtent[1]) /
72567 framebufferExtentDimension;
72568 u_tileOffset[2] = 2 * (tileExtent[0] - framebufferExtent[0]) /
72569 framebufferExtentDimension - 1;
72570 u_tileOffset[3] = 2 * (tileExtent[1] - framebufferExtent[1]) /
72571 framebufferExtentDimension - 1;
72572 gl.uniform4fv(this.locations_.u_tileOffset, u_tileOffset);
72573 mapRenderer.bindTileTexture(tile, tilePixelSize,
72574 tileGutter * pixelRatio, ol.webgl.LINEAR, ol.webgl.LINEAR);
72575 gl.drawArrays(ol.webgl.TRIANGLE_STRIP, 0, 4);
72576 }
72577 }
72578
72579 if (allTilesLoaded) {
72580 this.renderedTileRange_ = tileRange;
72581 this.renderedFramebufferExtent_ = framebufferExtent;
72582 this.renderedRevision_ = tileSource.getRevision();
72583 } else {
72584 this.renderedTileRange_ = null;
72585 this.renderedFramebufferExtent_ = null;
72586 this.renderedRevision_ = -1;
72587 frameState.animate = true;
72588 }
72589
72590 }
72591
72592 this.updateUsedTiles(frameState.usedTiles, tileSource, z, tileRange);
72593 var tileTextureQueue = mapRenderer.getTileTextureQueue();
72594 this.manageTilePyramid(
72595 frameState, tileSource, tileGrid, pixelRatio, projection, extent, z,
72596 tileLayer.getPreload(),
72597 /**
72598 * @param {ol.Tile} tile Tile.
72599 */
72600 function(tile) {
72601 if (tile.getState() == ol.TileState.LOADED &&
72602 !mapRenderer.isTileTextureLoaded(tile) &&
72603 !tileTextureQueue.isKeyQueued(tile.getKey())) {
72604 tileTextureQueue.enqueue([
72605 tile,
72606 tileGrid.getTileCoordCenter(tile.tileCoord),
72607 tileGrid.getResolution(tile.tileCoord[0]),
72608 tilePixelSize, tileGutter * pixelRatio
72609 ]);
72610 }
72611 }, this);
72612 this.scheduleExpireCache(frameState, tileSource);
72613 this.updateLogos(frameState, tileSource);
72614
72615 var texCoordMatrix = this.texCoordMatrix;
72616 ol.transform.reset(texCoordMatrix);
72617 ol.transform.translate(texCoordMatrix,
72618 (Math.round(center[0] / tileResolution) * tileResolution - framebufferExtent[0]) /
72619 (framebufferExtent[2] - framebufferExtent[0]),
72620 (Math.round(center[1] / tileResolution) * tileResolution - framebufferExtent[1]) /
72621 (framebufferExtent[3] - framebufferExtent[1]));
72622 if (viewState.rotation !== 0) {
72623 ol.transform.rotate(texCoordMatrix, viewState.rotation);
72624 }
72625 ol.transform.scale(texCoordMatrix,
72626 frameState.size[0] * viewState.resolution /
72627 (framebufferExtent[2] - framebufferExtent[0]),
72628 frameState.size[1] * viewState.resolution /
72629 (framebufferExtent[3] - framebufferExtent[1]));
72630 ol.transform.translate(texCoordMatrix, -0.5, -0.5);
72631
72632 return true;
72633 };
72634
72635
72636 /**
72637 * @inheritDoc
72638 */
72639 ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel = function(pixel, frameState, callback, thisArg) {
72640 if (!this.framebuffer) {
72641 return undefined;
72642 }
72643
72644 var pixelOnMapScaled = [
72645 pixel[0] / frameState.size[0],
72646 (frameState.size[1] - pixel[1]) / frameState.size[1]];
72647
72648 var pixelOnFrameBufferScaled = ol.transform.apply(
72649 this.texCoordMatrix, pixelOnMapScaled.slice());
72650 var pixelOnFrameBuffer = [
72651 pixelOnFrameBufferScaled[0] * this.framebufferDimension,
72652 pixelOnFrameBufferScaled[1] * this.framebufferDimension];
72653
72654 var gl = this.mapRenderer.getContext().getGL();
72655 gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
72656 var imageData = new Uint8Array(4);
72657 gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1,
72658 gl.RGBA, gl.UNSIGNED_BYTE, imageData);
72659
72660 if (imageData[3] > 0) {
72661 return callback.call(thisArg, this.getLayer(), imageData);
72662 } else {
72663 return undefined;
72664 }
72665 };
72666
72667}
72668
72669goog.provide('ol.layer.Tile');
72670
72671goog.require('ol');
72672goog.require('ol.layer.Layer');
72673goog.require('ol.layer.TileProperty');
72674goog.require('ol.obj');
72675goog.require('ol.renderer.Type');
72676goog.require('ol.renderer.canvas.TileLayer');
72677goog.require('ol.renderer.webgl.TileLayer');
72678
72679
72680/**
72681 * @classdesc
72682 * For layer sources that provide pre-rendered, tiled images in grids that are
72683 * organized by zoom levels for specific resolutions.
72684 * Note that any property set in the options is set as a {@link ol.Object}
72685 * property on the layer object; for example, setting `title: 'My Title'` in the
72686 * options means that `title` is observable, and has get/set accessors.
72687 *
72688 * @constructor
72689 * @extends {ol.layer.Layer}
72690 * @fires ol.render.Event
72691 * @param {olx.layer.TileOptions=} opt_options Tile layer options.
72692 * @api
72693 */
72694ol.layer.Tile = function(opt_options) {
72695 var options = opt_options ? opt_options : {};
72696
72697 var baseOptions = ol.obj.assign({}, options);
72698
72699 delete baseOptions.preload;
72700 delete baseOptions.useInterimTilesOnError;
72701 ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
72702
72703 this.setPreload(options.preload !== undefined ? options.preload : 0);
72704 this.setUseInterimTilesOnError(options.useInterimTilesOnError !== undefined ?
72705 options.useInterimTilesOnError : true);
72706};
72707ol.inherits(ol.layer.Tile, ol.layer.Layer);
72708
72709
72710/**
72711 * @inheritDoc
72712 */
72713ol.layer.Tile.prototype.createRenderer = function(mapRenderer) {
72714 var renderer = null;
72715 var type = mapRenderer.getType();
72716 if (ol.ENABLE_CANVAS && type === ol.renderer.Type.CANVAS) {
72717 renderer = new ol.renderer.canvas.TileLayer(this);
72718 } else if (ol.ENABLE_WEBGL && type === ol.renderer.Type.WEBGL) {
72719 renderer = new ol.renderer.webgl.TileLayer(/** @type {ol.renderer.webgl.Map} */ (mapRenderer), this);
72720 }
72721 return renderer;
72722};
72723
72724
72725/**
72726 * Return the level as number to which we will preload tiles up to.
72727 * @return {number} The level to preload tiles up to.
72728 * @observable
72729 * @api
72730 */
72731ol.layer.Tile.prototype.getPreload = function() {
72732 return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD));
72733};
72734
72735
72736/**
72737 * Return the associated {@link ol.source.Tile tilesource} of the layer.
72738 * @function
72739 * @return {ol.source.Tile} Source.
72740 * @api
72741 */
72742ol.layer.Tile.prototype.getSource;
72743
72744
72745/**
72746 * Set the level as number to which we will preload tiles up to.
72747 * @param {number} preload The level to preload tiles up to.
72748 * @observable
72749 * @api
72750 */
72751ol.layer.Tile.prototype.setPreload = function(preload) {
72752 this.set(ol.layer.TileProperty.PRELOAD, preload);
72753};
72754
72755
72756/**
72757 * Whether we use interim tiles on error.
72758 * @return {boolean} Use interim tiles on error.
72759 * @observable
72760 * @api
72761 */
72762ol.layer.Tile.prototype.getUseInterimTilesOnError = function() {
72763 return /** @type {boolean} */ (
72764 this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR));
72765};
72766
72767
72768/**
72769 * Set whether we use interim tiles on error.
72770 * @param {boolean} useInterimTilesOnError Use interim tiles on error.
72771 * @observable
72772 * @api
72773 */
72774ol.layer.Tile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {
72775 this.set(
72776 ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
72777};
72778
72779goog.provide('ol.layer.VectorTileRenderType');
72780
72781/**
72782 * @enum {string}
72783 * Render mode for vector tiles:
72784 * * `'image'`: Vector tiles are rendered as images. Great performance, but
72785 * point symbols and texts are always rotated with the view and pixels are
72786 * scaled during zoom animations.
72787 * * `'hybrid'`: Polygon and line elements are rendered as images, so pixels
72788 * are scaled during zoom animations. Point symbols and texts are accurately
72789 * rendered as vectors and can stay upright on rotated views.
72790 * * `'vector'`: Vector tiles are rendered as vectors. Most accurate rendering
72791 * even during animations, but slower performance than the other options.
72792 * @api
72793 */
72794ol.layer.VectorTileRenderType = {
72795 IMAGE: 'image',
72796 HYBRID: 'hybrid',
72797 VECTOR: 'vector'
72798};
72799
72800goog.provide('ol.renderer.canvas.VectorTileLayer');
72801
72802goog.require('ol');
72803goog.require('ol.TileState');
72804goog.require('ol.dom');
72805goog.require('ol.extent');
72806goog.require('ol.proj');
72807goog.require('ol.proj.Units');
72808goog.require('ol.layer.VectorTileRenderType');
72809goog.require('ol.render.ReplayType');
72810goog.require('ol.render.canvas');
72811goog.require('ol.render.canvas.ReplayGroup');
72812goog.require('ol.render.replay');
72813goog.require('ol.renderer.canvas.TileLayer');
72814goog.require('ol.renderer.vector');
72815goog.require('ol.size');
72816goog.require('ol.transform');
72817
72818
72819/**
72820 * @constructor
72821 * @extends {ol.renderer.canvas.TileLayer}
72822 * @param {ol.layer.VectorTile} layer VectorTile layer.
72823 */
72824ol.renderer.canvas.VectorTileLayer = function(layer) {
72825
72826 /**
72827 * @type {CanvasRenderingContext2D}
72828 */
72829 this.context = null;
72830
72831 ol.renderer.canvas.TileLayer.call(this, layer);
72832
72833 /**
72834 * @private
72835 * @type {boolean}
72836 */
72837 this.dirty_ = false;
72838
72839 /**
72840 * @private
72841 * @type {number}
72842 */
72843 this.renderedLayerRevision_;
72844
72845 /**
72846 * @private
72847 * @type {ol.Transform}
72848 */
72849 this.tmpTransform_ = ol.transform.create();
72850
72851 // Use lower resolution for pure vector rendering. Closest resolution otherwise.
72852 this.zDirection =
72853 layer.getRenderMode() == ol.layer.VectorTileRenderType.VECTOR ? 1 : 0;
72854
72855};
72856ol.inherits(ol.renderer.canvas.VectorTileLayer, ol.renderer.canvas.TileLayer);
72857
72858
72859/**
72860 * @const
72861 * @type {!Object.<string, Array.<ol.render.ReplayType>>}
72862 */
72863ol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS = {
72864 'image': [ol.render.ReplayType.POLYGON, ol.render.ReplayType.CIRCLE,
72865 ol.render.ReplayType.LINE_STRING, ol.render.ReplayType.IMAGE, ol.render.ReplayType.TEXT],
72866 'hybrid': [ol.render.ReplayType.POLYGON, ol.render.ReplayType.LINE_STRING]
72867};
72868
72869
72870/**
72871 * @const
72872 * @type {!Object.<string, Array.<ol.render.ReplayType>>}
72873 */
72874ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS = {
72875 'image': [ol.render.ReplayType.DEFAULT],
72876 'hybrid': [ol.render.ReplayType.IMAGE, ol.render.ReplayType.TEXT, ol.render.ReplayType.DEFAULT],
72877 'vector': ol.render.replay.ORDER
72878};
72879
72880
72881/**
72882 * @inheritDoc
72883 */
72884ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = function(frameState, layerState) {
72885 var layer = this.getLayer();
72886 var layerRevision = layer.getRevision();
72887 if (this.renderedLayerRevision_ != layerRevision) {
72888 this.renderedTiles.length = 0;
72889 var renderMode = layer.getRenderMode();
72890 if (!this.context && renderMode != ol.layer.VectorTileRenderType.VECTOR) {
72891 this.context = ol.dom.createCanvasContext2D();
72892 }
72893 if (this.context && renderMode == ol.layer.VectorTileRenderType.VECTOR) {
72894 this.context = null;
72895 }
72896 }
72897 this.renderedLayerRevision_ = layerRevision;
72898 return ol.renderer.canvas.TileLayer.prototype.prepareFrame.apply(this, arguments);
72899};
72900
72901
72902/**
72903 * @param {ol.VectorImageTile} tile Tile.
72904 * @param {olx.FrameState} frameState Frame state.
72905 * @private
72906 */
72907ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup_ = function(
72908 tile, frameState) {
72909 var layer = this.getLayer();
72910 var pixelRatio = frameState.pixelRatio;
72911 var projection = frameState.viewState.projection;
72912 var revision = layer.getRevision();
72913 var renderOrder = /** @type {ol.RenderOrderFunction} */
72914 (layer.getRenderOrder()) || null;
72915
72916 var replayState = tile.getReplayState(layer);
72917 if (!replayState.dirty && replayState.renderedRevision == revision &&
72918 replayState.renderedRenderOrder == renderOrder) {
72919 return;
72920 }
72921
72922 var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
72923 var sourceTileGrid = source.getTileGrid();
72924 var tileGrid = source.getTileGridForProjection(projection);
72925 var resolution = tileGrid.getResolution(tile.tileCoord[0]);
72926 var tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord);
72927
72928 for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
72929 var sourceTile = tile.getTile(tile.tileKeys[t]);
72930 replayState.dirty = false;
72931
72932 var sourceTileCoord = sourceTile.tileCoord;
72933 var tileProjection = sourceTile.getProjection();
72934 var sourceTileResolution = sourceTileGrid.getResolution(sourceTile.tileCoord[0]);
72935 var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord);
72936 var sharedExtent = ol.extent.getIntersection(tileExtent, sourceTileExtent);
72937 var extent, reproject, tileResolution;
72938 if (tileProjection.getUnits() == ol.proj.Units.TILE_PIXELS) {
72939 var tilePixelRatio = tileResolution = this.getTilePixelRatio_(source, sourceTile);
72940 var transform = ol.transform.compose(this.tmpTransform_,
72941 0, 0,
72942 1 / sourceTileResolution * tilePixelRatio, -1 / sourceTileResolution * tilePixelRatio,
72943 0,
72944 -sourceTileExtent[0], -sourceTileExtent[3]);
72945 extent = (ol.transform.apply(transform, [sharedExtent[0], sharedExtent[3]])
72946 .concat(ol.transform.apply(transform, [sharedExtent[2], sharedExtent[1]])));
72947 } else {
72948 tileResolution = resolution;
72949 extent = sharedExtent;
72950 if (!ol.proj.equivalent(projection, tileProjection)) {
72951 reproject = true;
72952 sourceTile.setProjection(projection);
72953 }
72954 }
72955 replayState.dirty = false;
72956 var replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
72957 tileResolution, source.getOverlaps(), layer.getRenderBuffer());
72958 var squaredTolerance = ol.renderer.vector.getSquaredTolerance(
72959 tileResolution, pixelRatio);
72960
72961 /**
72962 * @param {ol.Feature|ol.render.Feature} feature Feature.
72963 * @this {ol.renderer.canvas.VectorTileLayer}
72964 */
72965 var renderFeature = function(feature) {
72966 var styles;
72967 var styleFunction = feature.getStyleFunction();
72968 if (styleFunction) {
72969 styles = styleFunction.call(/** @type {ol.Feature} */ (feature), resolution);
72970 } else {
72971 styleFunction = layer.getStyleFunction();
72972 if (styleFunction) {
72973 styles = styleFunction(feature, resolution);
72974 }
72975 }
72976 if (styles) {
72977 if (!Array.isArray(styles)) {
72978 styles = [styles];
72979 }
72980 var dirty = this.renderFeature(feature, squaredTolerance, styles,
72981 replayGroup);
72982 this.dirty_ = this.dirty_ || dirty;
72983 replayState.dirty = replayState.dirty || dirty;
72984 }
72985 };
72986
72987 var features = sourceTile.getFeatures();
72988 if (renderOrder && renderOrder !== replayState.renderedRenderOrder) {
72989 features.sort(renderOrder);
72990 }
72991 var feature;
72992 for (var i = 0, ii = features.length; i < ii; ++i) {
72993 feature = features[i];
72994 if (reproject) {
72995 feature.getGeometry().transform(tileProjection, projection);
72996 }
72997 renderFeature.call(this, feature);
72998 }
72999 replayGroup.finish();
73000 sourceTile.setReplayGroup(layer, tile.tileCoord.toString(), replayGroup);
73001 }
73002 replayState.renderedRevision = revision;
73003 replayState.renderedRenderOrder = renderOrder;
73004};
73005
73006
73007/**
73008 * @inheritDoc
73009 */
73010ol.renderer.canvas.VectorTileLayer.prototype.drawTileImage = function(
73011 tile, frameState, layerState, x, y, w, h, gutter) {
73012 var vectorImageTile = /** @type {ol.VectorImageTile} */ (tile);
73013 this.createReplayGroup_(vectorImageTile, frameState);
73014 if (this.context) {
73015 this.renderTileImage_(vectorImageTile, frameState, layerState);
73016 ol.renderer.canvas.TileLayer.prototype.drawTileImage.apply(this, arguments);
73017 }
73018};
73019
73020
73021/**
73022 * @inheritDoc
73023 */
73024ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = function(coordinate, frameState, hitTolerance, callback, thisArg) {
73025 var resolution = frameState.viewState.resolution;
73026 var rotation = frameState.viewState.rotation;
73027 hitTolerance = hitTolerance == undefined ? 0 : hitTolerance;
73028 var layer = this.getLayer();
73029 /** @type {Object.<string, boolean>} */
73030 var features = {};
73031
73032 /** @type {Array.<ol.VectorImageTile>} */
73033 var renderedTiles = this.renderedTiles;
73034
73035 var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
73036 var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
73037 var sourceTileGrid = source.getTileGrid();
73038 var bufferedExtent, found, tileSpaceCoordinate;
73039 var i, ii, origin, replayGroup;
73040 var tile, tileCoord, tileExtent, tilePixelRatio, tileRenderResolution;
73041 for (i = 0, ii = renderedTiles.length; i < ii; ++i) {
73042 tile = renderedTiles[i];
73043 tileCoord = tile.tileCoord;
73044 tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
73045 bufferedExtent = ol.extent.buffer(tileExtent, hitTolerance * resolution, bufferedExtent);
73046 if (!ol.extent.containsCoordinate(bufferedExtent, coordinate)) {
73047 continue;
73048 }
73049 for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
73050 var sourceTile = tile.getTile(tile.tileKeys[t]);
73051 if (sourceTile.getProjection().getUnits() === ol.proj.Units.TILE_PIXELS) {
73052 var sourceTileCoord = sourceTile.tileCoord;
73053 var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
73054 origin = ol.extent.getTopLeft(sourceTileExtent);
73055 tilePixelRatio = this.getTilePixelRatio_(source, sourceTile);
73056 var sourceTileResolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
73057 tileRenderResolution = sourceTileResolution / tilePixelRatio;
73058 tileSpaceCoordinate = [
73059 (coordinate[0] - origin[0]) / tileRenderResolution,
73060 (origin[1] - coordinate[1]) / tileRenderResolution
73061 ];
73062 var upscaling = tileGrid.getResolution(tileCoord[0]) / sourceTileResolution;
73063 resolution = tilePixelRatio * upscaling;
73064 } else {
73065 tileSpaceCoordinate = coordinate;
73066 }
73067 replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString());
73068 found = found || replayGroup.forEachFeatureAtCoordinate(
73069 tileSpaceCoordinate, resolution, rotation, hitTolerance, {},
73070 /**
73071 * @param {ol.Feature|ol.render.Feature} feature Feature.
73072 * @return {?} Callback result.
73073 */
73074 function(feature) {
73075 var key = ol.getUid(feature).toString();
73076 if (!(key in features)) {
73077 features[key] = true;
73078 return callback.call(thisArg, feature, layer);
73079 }
73080 });
73081 }
73082 }
73083 return found;
73084};
73085
73086
73087/**
73088 * @param {ol.VectorTile} tile Tile.
73089 * @param {olx.FrameState} frameState Frame state.
73090 * @return {ol.Transform} transform Transform.
73091 * @private
73092 */
73093ol.renderer.canvas.VectorTileLayer.prototype.getReplayTransform_ = function(tile, frameState) {
73094 if (tile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
73095 var layer = this.getLayer();
73096 var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
73097 var tileGrid = source.getTileGrid();
73098 var tileCoord = tile.tileCoord;
73099 var tileResolution =
73100 tileGrid.getResolution(tileCoord[0]) / this.getTilePixelRatio_(source, tile);
73101 var viewState = frameState.viewState;
73102 var pixelRatio = frameState.pixelRatio;
73103 var renderResolution = viewState.resolution / pixelRatio;
73104 var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent);
73105 var center = viewState.center;
73106 var origin = ol.extent.getTopLeft(tileExtent);
73107 var size = frameState.size;
73108 var offsetX = Math.round(pixelRatio * size[0] / 2);
73109 var offsetY = Math.round(pixelRatio * size[1] / 2);
73110 return ol.transform.compose(this.tmpTransform_,
73111 offsetX, offsetY,
73112 tileResolution / renderResolution, tileResolution / renderResolution,
73113 viewState.rotation,
73114 (origin[0] - center[0]) / tileResolution,
73115 (center[1] - origin[1]) / tileResolution);
73116 } else {
73117 return this.getTransform(frameState, 0);
73118 }
73119};
73120
73121
73122/**
73123 * @private
73124 * @param {ol.source.VectorTile} source Source.
73125 * @param {ol.VectorTile} tile Tile.
73126 * @return {number} The tile's pixel ratio.
73127 */
73128ol.renderer.canvas.VectorTileLayer.prototype.getTilePixelRatio_ = function(source, tile) {
73129 return ol.extent.getWidth(tile.getExtent()) /
73130 ol.size.toSize(source.getTileGrid().getTileSize(tile.tileCoord[0]))[0];
73131};
73132
73133
73134/**
73135 * Handle changes in image style state.
73136 * @param {ol.events.Event} event Image style change event.
73137 * @private
73138 */
73139ol.renderer.canvas.VectorTileLayer.prototype.handleStyleImageChange_ = function(event) {
73140 this.renderIfReadyAndVisible();
73141};
73142
73143
73144/**
73145 * @inheritDoc
73146 */
73147ol.renderer.canvas.VectorTileLayer.prototype.postCompose = function(context, frameState, layerState) {
73148 var layer = this.getLayer();
73149 var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
73150 var renderMode = layer.getRenderMode();
73151 var replays = ol.renderer.canvas.VectorTileLayer.VECTOR_REPLAYS[renderMode];
73152 var pixelRatio = frameState.pixelRatio;
73153 var rotation = frameState.viewState.rotation;
73154 var size = frameState.size;
73155 var offsetX = Math.round(pixelRatio * size[0] / 2);
73156 var offsetY = Math.round(pixelRatio * size[1] / 2);
73157 var tiles = this.renderedTiles;
73158 var sourceTileGrid = source.getTileGrid();
73159 var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
73160 var clips = [];
73161 var zs = [];
73162 for (var i = tiles.length - 1; i >= 0; --i) {
73163 var tile = /** @type {ol.VectorImageTile} */ (tiles[i]);
73164 if (tile.getState() == ol.TileState.ABORT) {
73165 continue;
73166 }
73167 var tileCoord = tile.tileCoord;
73168 var worldOffset = tileGrid.getTileCoordExtent(tileCoord)[0] -
73169 tileGrid.getTileCoordExtent(tile.wrappedTileCoord)[0];
73170 for (var t = 0, tt = tile.tileKeys.length; t < tt; ++t) {
73171 var sourceTile = tile.getTile(tile.tileKeys[t]);
73172 var tilePixelRatio = this.getTilePixelRatio_(source, sourceTile);
73173 var replayGroup = sourceTile.getReplayGroup(layer, tileCoord.toString());
73174 if (renderMode != ol.layer.VectorTileRenderType.VECTOR && !replayGroup.hasReplays(replays)) {
73175 continue;
73176 }
73177 var currentZ = sourceTile.tileCoord[0];
73178 var sourceResolution = sourceTileGrid.getResolution(currentZ);
73179 var transform = this.getReplayTransform_(sourceTile, frameState);
73180 ol.transform.translate(transform, worldOffset * tilePixelRatio / sourceResolution, 0);
73181 var currentClip = replayGroup.getClipCoords(transform);
73182 context.save();
73183 context.globalAlpha = layerState.opacity;
73184 ol.render.canvas.rotateAtOffset(context, -rotation, offsetX, offsetY);
73185 // Create a clip mask for regions in this low resolution tile that are
73186 // already filled by a higher resolution tile
73187 for (var j = 0, jj = clips.length; j < jj; ++j) {
73188 var clip = clips[j];
73189 if (currentZ < zs[j]) {
73190 context.beginPath();
73191 // counter-clockwise (outer ring) for current tile
73192 context.moveTo(currentClip[0], currentClip[1]);
73193 context.lineTo(currentClip[2], currentClip[3]);
73194 context.lineTo(currentClip[4], currentClip[5]);
73195 context.lineTo(currentClip[6], currentClip[7]);
73196 // clockwise (inner ring) for higher resolution tile
73197 context.moveTo(clip[6], clip[7]);
73198 context.lineTo(clip[4], clip[5]);
73199 context.lineTo(clip[2], clip[3]);
73200 context.lineTo(clip[0], clip[1]);
73201 context.clip();
73202 }
73203 }
73204 replayGroup.replay(context, pixelRatio, transform, rotation, {}, replays);
73205 context.restore();
73206 clips.push(currentClip);
73207 zs.push(currentZ);
73208 }
73209 }
73210 ol.renderer.canvas.TileLayer.prototype.postCompose.apply(this, arguments);
73211};
73212
73213
73214/**
73215 * @param {ol.Feature|ol.render.Feature} feature Feature.
73216 * @param {number} squaredTolerance Squared tolerance.
73217 * @param {(ol.style.Style|Array.<ol.style.Style>)} styles The style or array of
73218 * styles.
73219 * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group.
73220 * @return {boolean} `true` if an image is loading.
73221 */
73222ol.renderer.canvas.VectorTileLayer.prototype.renderFeature = function(feature, squaredTolerance, styles, replayGroup) {
73223 if (!styles) {
73224 return false;
73225 }
73226 var loading = false;
73227 if (Array.isArray(styles)) {
73228 for (var i = 0, ii = styles.length; i < ii; ++i) {
73229 loading = ol.renderer.vector.renderFeature(
73230 replayGroup, feature, styles[i], squaredTolerance,
73231 this.handleStyleImageChange_, this) || loading;
73232 }
73233 } else {
73234 loading = ol.renderer.vector.renderFeature(
73235 replayGroup, feature, styles, squaredTolerance,
73236 this.handleStyleImageChange_, this) || loading;
73237 }
73238 return loading;
73239};
73240
73241
73242/**
73243 * @param {ol.VectorImageTile} tile Tile.
73244 * @param {olx.FrameState} frameState Frame state.
73245 * @param {ol.LayerState} layerState Layer state.
73246 * @private
73247 */
73248ol.renderer.canvas.VectorTileLayer.prototype.renderTileImage_ = function(
73249 tile, frameState, layerState) {
73250 var layer = this.getLayer();
73251 var replayState = tile.getReplayState(layer);
73252 var revision = layer.getRevision();
73253 var replays = ol.renderer.canvas.VectorTileLayer.IMAGE_REPLAYS[layer.getRenderMode()];
73254 if (replays && replayState.renderedTileRevision !== revision) {
73255 replayState.renderedTileRevision = revision;
73256 var tileCoord = tile.wrappedTileCoord;
73257 var z = tileCoord[0];
73258 var pixelRatio = frameState.pixelRatio;
73259 var source = /** @type {ol.source.VectorTile} */ (layer.getSource());
73260 var sourceTileGrid = source.getTileGrid();
73261 var tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
73262 var resolution = tileGrid.getResolution(z);
73263 var context = tile.getContext(layer);
73264 var size = source.getTilePixelSize(z, pixelRatio, frameState.viewState.projection);
73265 context.canvas.width = size[0];
73266 context.canvas.height = size[1];
73267 var tileExtent = tileGrid.getTileCoordExtent(tileCoord);
73268 for (var i = 0, ii = tile.tileKeys.length; i < ii; ++i) {
73269 var sourceTile = tile.getTile(tile.tileKeys[i]);
73270 var tilePixelRatio = this.getTilePixelRatio_(source, sourceTile);
73271 var sourceTileCoord = sourceTile.tileCoord;
73272 var pixelScale = pixelRatio / resolution;
73273 var transform = ol.transform.reset(this.tmpTransform_);
73274 if (sourceTile.getProjection().getUnits() == ol.proj.Units.TILE_PIXELS) {
73275 var sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord, this.tmpExtent);
73276 var sourceResolution = sourceTileGrid.getResolution(sourceTileCoord[0]);
73277 var renderPixelRatio = pixelRatio / tilePixelRatio * sourceResolution / resolution;
73278 ol.transform.scale(transform, renderPixelRatio, renderPixelRatio);
73279 var offsetX = (sourceTileExtent[0] - tileExtent[0]) / sourceResolution * tilePixelRatio;
73280 var offsetY = (tileExtent[3] - sourceTileExtent[3]) / sourceResolution * tilePixelRatio;
73281 ol.transform.translate(transform, Math.round(offsetX), Math.round(offsetY));
73282 } else {
73283 ol.transform.scale(transform, pixelScale, -pixelScale);
73284 ol.transform.translate(transform, -tileExtent[0], -tileExtent[3]);
73285 }
73286 var replayGroup = sourceTile.getReplayGroup(layer, tile.tileCoord.toString());
73287 replayGroup.replay(context, pixelRatio, transform, 0, {}, replays, true);
73288 }
73289 }
73290};
73291
73292goog.provide('ol.layer.VectorTile');
73293
73294goog.require('ol');
73295goog.require('ol.asserts');
73296goog.require('ol.layer.TileProperty');
73297goog.require('ol.layer.Vector');
73298goog.require('ol.layer.VectorTileRenderType');
73299goog.require('ol.obj');
73300goog.require('ol.renderer.Type');
73301goog.require('ol.renderer.canvas.VectorTileLayer');
73302
73303
73304/**
73305 * @classdesc
73306 * Layer for vector tile data that is rendered client-side.
73307 * Note that any property set in the options is set as a {@link ol.Object}
73308 * property on the layer object; for example, setting `title: 'My Title'` in the
73309 * options means that `title` is observable, and has get/set accessors.
73310 *
73311 * @constructor
73312 * @extends {ol.layer.Vector}
73313 * @param {olx.layer.VectorTileOptions=} opt_options Options.
73314 * @api
73315 */
73316ol.layer.VectorTile = function(opt_options) {
73317 var options = opt_options ? opt_options : {};
73318
73319 var baseOptions = ol.obj.assign({}, options);
73320
73321 delete baseOptions.preload;
73322 delete baseOptions.useInterimTilesOnError;
73323 ol.layer.Vector.call(this, /** @type {olx.layer.VectorOptions} */ (baseOptions));
73324
73325 this.setPreload(options.preload ? options.preload : 0);
73326 this.setUseInterimTilesOnError(options.useInterimTilesOnError ?
73327 options.useInterimTilesOnError : true);
73328
73329 ol.asserts.assert(options.renderMode == undefined ||
73330 options.renderMode == ol.layer.VectorTileRenderType.IMAGE ||
73331 options.renderMode == ol.layer.VectorTileRenderType.HYBRID ||
73332 options.renderMode == ol.layer.VectorTileRenderType.VECTOR,
73333 28); // `renderMode` must be `'image'`, `'hybrid'` or `'vector'`
73334
73335 /**
73336 * @private
73337 * @type {ol.layer.VectorTileRenderType|string}
73338 */
73339 this.renderMode_ = options.renderMode || ol.layer.VectorTileRenderType.HYBRID;
73340
73341};
73342ol.inherits(ol.layer.VectorTile, ol.layer.Vector);
73343
73344
73345/**
73346 * @inheritDoc
73347 */
73348ol.layer.VectorTile.prototype.createRenderer = function(mapRenderer) {
73349 var renderer = null;
73350 var type = mapRenderer.getType();
73351 if (ol.ENABLE_CANVAS && type === ol.renderer.Type.CANVAS) {
73352 renderer = new ol.renderer.canvas.VectorTileLayer(this);
73353 }
73354 return renderer;
73355};
73356
73357
73358/**
73359 * Return the level as number to which we will preload tiles up to.
73360 * @return {number} The level to preload tiles up to.
73361 * @observable
73362 * @api
73363 */
73364ol.layer.VectorTile.prototype.getPreload = function() {
73365 return /** @type {number} */ (this.get(ol.layer.TileProperty.PRELOAD));
73366};
73367
73368
73369/**
73370 * @return {ol.layer.VectorTileRenderType|string} The render mode.
73371 */
73372ol.layer.VectorTile.prototype.getRenderMode = function() {
73373 return this.renderMode_;
73374};
73375
73376
73377/**
73378 * Whether we use interim tiles on error.
73379 * @return {boolean} Use interim tiles on error.
73380 * @observable
73381 * @api
73382 */
73383ol.layer.VectorTile.prototype.getUseInterimTilesOnError = function() {
73384 return /** @type {boolean} */ (
73385 this.get(ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR));
73386};
73387
73388
73389/**
73390 * Set the level as number to which we will preload tiles up to.
73391 * @param {number} preload The level to preload tiles up to.
73392 * @observable
73393 * @api
73394 */
73395ol.layer.VectorTile.prototype.setPreload = function(preload) {
73396 this.set(ol.layer.TileProperty.PRELOAD, preload);
73397};
73398
73399
73400/**
73401 * Set whether we use interim tiles on error.
73402 * @param {boolean} useInterimTilesOnError Use interim tiles on error.
73403 * @observable
73404 * @api
73405 */
73406ol.layer.VectorTile.prototype.setUseInterimTilesOnError = function(useInterimTilesOnError) {
73407 this.set(
73408 ol.layer.TileProperty.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError);
73409};
73410
73411
73412/**
73413 * Return the associated {@link ol.source.VectorTile vectortilesource} of the layer.
73414 * @function
73415 * @return {ol.source.VectorTile} Source.
73416 * @api
73417 */
73418ol.layer.VectorTile.prototype.getSource;
73419
73420goog.provide('ol.net');
73421
73422goog.require('ol');
73423
73424
73425/**
73426 * Simple JSONP helper. Supports error callbacks and a custom callback param.
73427 * The error callback will be called when no JSONP is executed after 10 seconds.
73428 *
73429 * @param {string} url Request url. A 'callback' query parameter will be
73430 * appended.
73431 * @param {Function} callback Callback on success.
73432 * @param {function()=} opt_errback Callback on error.
73433 * @param {string=} opt_callbackParam Custom query parameter for the JSONP
73434 * callback. Default is 'callback'.
73435 */
73436ol.net.jsonp = function(url, callback, opt_errback, opt_callbackParam) {
73437 var script = document.createElement('script');
73438 var key = 'olc_' + ol.getUid(callback);
73439 function cleanup() {
73440 delete window[key];
73441 script.parentNode.removeChild(script);
73442 }
73443 script.async = true;
73444 script.src = url + (url.indexOf('?') == -1 ? '?' : '&') +
73445 (opt_callbackParam || 'callback') + '=' + key;
73446 var timer = setTimeout(function() {
73447 cleanup();
73448 if (opt_errback) {
73449 opt_errback();
73450 }
73451 }, 10000);
73452 window[key] = function(data) {
73453 clearTimeout(timer);
73454 cleanup();
73455 callback(data);
73456 };
73457 document.getElementsByTagName('head')[0].appendChild(script);
73458};
73459
73460goog.provide('ol.proj.common');
73461
73462goog.require('ol.proj');
73463
73464
73465/**
73466 * Deprecated. Transforms between EPSG:4326 and EPSG:3857 are now included by
73467 * default. There is no need to call this function in application code and it
73468 * will be removed in a future major release.
73469 * @deprecated This function is no longer necessary.
73470 * @api
73471 */
73472ol.proj.common.add = ol.proj.addCommon;
73473
73474goog.provide('ol.render');
73475
73476goog.require('ol.has');
73477goog.require('ol.transform');
73478goog.require('ol.render.canvas.Immediate');
73479
73480
73481/**
73482 * Binds a Canvas Immediate API to a canvas context, to allow drawing geometries
73483 * to the context's canvas.
73484 *
73485 * The units for geometry coordinates are css pixels relative to the top left
73486 * corner of the canvas element.
73487 * ```js
73488 * var canvas = document.createElement('canvas');
73489 * var render = ol.render.toContext(canvas.getContext('2d'),
73490 * { size: [100, 100] });
73491 * render.setFillStrokeStyle(new ol.style.Fill({ color: blue }));
73492 * render.drawPolygon(
73493 * new ol.geom.Polygon([[[0, 0], [100, 100], [100, 0], [0, 0]]]));
73494 * ```
73495 *
73496 * @param {CanvasRenderingContext2D} context Canvas context.
73497 * @param {olx.render.ToContextOptions=} opt_options Options.
73498 * @return {ol.render.canvas.Immediate} Canvas Immediate.
73499 * @api
73500 */
73501ol.render.toContext = function(context, opt_options) {
73502 var canvas = context.canvas;
73503 var options = opt_options ? opt_options : {};
73504 var pixelRatio = options.pixelRatio || ol.has.DEVICE_PIXEL_RATIO;
73505 var size = options.size;
73506 if (size) {
73507 canvas.width = size[0] * pixelRatio;
73508 canvas.height = size[1] * pixelRatio;
73509 canvas.style.width = size[0] + 'px';
73510 canvas.style.height = size[1] + 'px';
73511 }
73512 var extent = [0, 0, canvas.width, canvas.height];
73513 var transform = ol.transform.scale(ol.transform.create(), pixelRatio, pixelRatio);
73514 return new ol.render.canvas.Immediate(context, pixelRatio, extent, transform,
73515 0);
73516};
73517
73518goog.provide('ol.reproj.Tile');
73519
73520goog.require('ol');
73521goog.require('ol.Tile');
73522goog.require('ol.TileState');
73523goog.require('ol.events');
73524goog.require('ol.events.EventType');
73525goog.require('ol.extent');
73526goog.require('ol.math');
73527goog.require('ol.reproj');
73528goog.require('ol.reproj.Triangulation');
73529
73530
73531/**
73532 * @classdesc
73533 * Class encapsulating single reprojected tile.
73534 * See {@link ol.source.TileImage}.
73535 *
73536 * @constructor
73537 * @extends {ol.Tile}
73538 * @param {ol.proj.Projection} sourceProj Source projection.
73539 * @param {ol.tilegrid.TileGrid} sourceTileGrid Source tile grid.
73540 * @param {ol.proj.Projection} targetProj Target projection.
73541 * @param {ol.tilegrid.TileGrid} targetTileGrid Target tile grid.
73542 * @param {ol.TileCoord} tileCoord Coordinate of the tile.
73543 * @param {ol.TileCoord} wrappedTileCoord Coordinate of the tile wrapped in X.
73544 * @param {number} pixelRatio Pixel ratio.
73545 * @param {number} gutter Gutter of the source tiles.
73546 * @param {ol.ReprojTileFunctionType} getTileFunction
73547 * Function returning source tiles (z, x, y, pixelRatio).
73548 * @param {number=} opt_errorThreshold Acceptable reprojection error (in px).
73549 * @param {boolean=} opt_renderEdges Render reprojection edges.
73550 */
73551ol.reproj.Tile = function(sourceProj, sourceTileGrid,
73552 targetProj, targetTileGrid, tileCoord, wrappedTileCoord,
73553 pixelRatio, gutter, getTileFunction,
73554 opt_errorThreshold,
73555 opt_renderEdges) {
73556 ol.Tile.call(this, tileCoord, ol.TileState.IDLE);
73557
73558 /**
73559 * @private
73560 * @type {boolean}
73561 */
73562 this.renderEdges_ = opt_renderEdges !== undefined ? opt_renderEdges : false;
73563
73564 /**
73565 * @private
73566 * @type {number}
73567 */
73568 this.pixelRatio_ = pixelRatio;
73569
73570 /**
73571 * @private
73572 * @type {number}
73573 */
73574 this.gutter_ = gutter;
73575
73576 /**
73577 * @private
73578 * @type {HTMLCanvasElement}
73579 */
73580 this.canvas_ = null;
73581
73582 /**
73583 * @private
73584 * @type {ol.tilegrid.TileGrid}
73585 */
73586 this.sourceTileGrid_ = sourceTileGrid;
73587
73588 /**
73589 * @private
73590 * @type {ol.tilegrid.TileGrid}
73591 */
73592 this.targetTileGrid_ = targetTileGrid;
73593
73594 /**
73595 * @private
73596 * @type {ol.TileCoord}
73597 */
73598 this.wrappedTileCoord_ = wrappedTileCoord ? wrappedTileCoord : tileCoord;
73599
73600 /**
73601 * @private
73602 * @type {!Array.<ol.Tile>}
73603 */
73604 this.sourceTiles_ = [];
73605
73606 /**
73607 * @private
73608 * @type {Array.<ol.EventsKey>}
73609 */
73610 this.sourcesListenerKeys_ = null;
73611
73612 /**
73613 * @private
73614 * @type {number}
73615 */
73616 this.sourceZ_ = 0;
73617
73618 var targetExtent = targetTileGrid.getTileCoordExtent(this.wrappedTileCoord_);
73619 var maxTargetExtent = this.targetTileGrid_.getExtent();
73620 var maxSourceExtent = this.sourceTileGrid_.getExtent();
73621
73622 var limitedTargetExtent = maxTargetExtent ?
73623 ol.extent.getIntersection(targetExtent, maxTargetExtent) : targetExtent;
73624
73625 if (ol.extent.getArea(limitedTargetExtent) === 0) {
73626 // Tile is completely outside range -> EMPTY
73627 // TODO: is it actually correct that the source even creates the tile ?
73628 this.state = ol.TileState.EMPTY;
73629 return;
73630 }
73631
73632 var sourceProjExtent = sourceProj.getExtent();
73633 if (sourceProjExtent) {
73634 if (!maxSourceExtent) {
73635 maxSourceExtent = sourceProjExtent;
73636 } else {
73637 maxSourceExtent = ol.extent.getIntersection(
73638 maxSourceExtent, sourceProjExtent);
73639 }
73640 }
73641
73642 var targetResolution = targetTileGrid.getResolution(
73643 this.wrappedTileCoord_[0]);
73644
73645 var targetCenter = ol.extent.getCenter(limitedTargetExtent);
73646 var sourceResolution = ol.reproj.calculateSourceResolution(
73647 sourceProj, targetProj, targetCenter, targetResolution);
73648
73649 if (!isFinite(sourceResolution) || sourceResolution <= 0) {
73650 // invalid sourceResolution -> EMPTY
73651 // probably edges of the projections when no extent is defined
73652 this.state = ol.TileState.EMPTY;
73653 return;
73654 }
73655
73656 var errorThresholdInPixels = opt_errorThreshold !== undefined ?
73657 opt_errorThreshold : ol.DEFAULT_RASTER_REPROJECTION_ERROR_THRESHOLD;
73658
73659 /**
73660 * @private
73661 * @type {!ol.reproj.Triangulation}
73662 */
73663 this.triangulation_ = new ol.reproj.Triangulation(
73664 sourceProj, targetProj, limitedTargetExtent, maxSourceExtent,
73665 sourceResolution * errorThresholdInPixels);
73666
73667 if (this.triangulation_.getTriangles().length === 0) {
73668 // no valid triangles -> EMPTY
73669 this.state = ol.TileState.EMPTY;
73670 return;
73671 }
73672
73673 this.sourceZ_ = sourceTileGrid.getZForResolution(sourceResolution);
73674 var sourceExtent = this.triangulation_.calculateSourceExtent();
73675
73676 if (maxSourceExtent) {
73677 if (sourceProj.canWrapX()) {
73678 sourceExtent[1] = ol.math.clamp(
73679 sourceExtent[1], maxSourceExtent[1], maxSourceExtent[3]);
73680 sourceExtent[3] = ol.math.clamp(
73681 sourceExtent[3], maxSourceExtent[1], maxSourceExtent[3]);
73682 } else {
73683 sourceExtent = ol.extent.getIntersection(sourceExtent, maxSourceExtent);
73684 }
73685 }
73686
73687 if (!ol.extent.getArea(sourceExtent)) {
73688 this.state = ol.TileState.EMPTY;
73689 } else {
73690 var sourceRange = sourceTileGrid.getTileRangeForExtentAndZ(
73691 sourceExtent, this.sourceZ_);
73692
73693 for (var srcX = sourceRange.minX; srcX <= sourceRange.maxX; srcX++) {
73694 for (var srcY = sourceRange.minY; srcY <= sourceRange.maxY; srcY++) {
73695 var tile = getTileFunction(this.sourceZ_, srcX, srcY, pixelRatio);
73696 if (tile) {
73697 this.sourceTiles_.push(tile);
73698 }
73699 }
73700 }
73701
73702 if (this.sourceTiles_.length === 0) {
73703 this.state = ol.TileState.EMPTY;
73704 }
73705 }
73706};
73707ol.inherits(ol.reproj.Tile, ol.Tile);
73708
73709
73710/**
73711 * @inheritDoc
73712 */
73713ol.reproj.Tile.prototype.disposeInternal = function() {
73714 if (this.state == ol.TileState.LOADING) {
73715 this.unlistenSources_();
73716 }
73717 ol.Tile.prototype.disposeInternal.call(this);
73718};
73719
73720
73721/**
73722 * Get the HTML Canvas element for this tile.
73723 * @return {HTMLCanvasElement} Canvas.
73724 */
73725ol.reproj.Tile.prototype.getImage = function() {
73726 return this.canvas_;
73727};
73728
73729
73730/**
73731 * @private
73732 */
73733ol.reproj.Tile.prototype.reproject_ = function() {
73734 var sources = [];
73735 this.sourceTiles_.forEach(function(tile, i, arr) {
73736 if (tile && tile.getState() == ol.TileState.LOADED) {
73737 sources.push({
73738 extent: this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord),
73739 image: tile.getImage()
73740 });
73741 }
73742 }, this);
73743 this.sourceTiles_.length = 0;
73744
73745 if (sources.length === 0) {
73746 this.state = ol.TileState.ERROR;
73747 } else {
73748 var z = this.wrappedTileCoord_[0];
73749 var size = this.targetTileGrid_.getTileSize(z);
73750 var width = typeof size === 'number' ? size : size[0];
73751 var height = typeof size === 'number' ? size : size[1];
73752 var targetResolution = this.targetTileGrid_.getResolution(z);
73753 var sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_);
73754
73755 var targetExtent = this.targetTileGrid_.getTileCoordExtent(
73756 this.wrappedTileCoord_);
73757 this.canvas_ = ol.reproj.render(width, height, this.pixelRatio_,
73758 sourceResolution, this.sourceTileGrid_.getExtent(),
73759 targetResolution, targetExtent, this.triangulation_, sources,
73760 this.gutter_, this.renderEdges_);
73761
73762 this.state = ol.TileState.LOADED;
73763 }
73764 this.changed();
73765};
73766
73767
73768/**
73769 * @inheritDoc
73770 */
73771ol.reproj.Tile.prototype.load = function() {
73772 if (this.state == ol.TileState.IDLE) {
73773 this.state = ol.TileState.LOADING;
73774 this.changed();
73775
73776 var leftToLoad = 0;
73777
73778 this.sourcesListenerKeys_ = [];
73779 this.sourceTiles_.forEach(function(tile, i, arr) {
73780 var state = tile.getState();
73781 if (state == ol.TileState.IDLE || state == ol.TileState.LOADING) {
73782 leftToLoad++;
73783
73784 var sourceListenKey;
73785 sourceListenKey = ol.events.listen(tile, ol.events.EventType.CHANGE,
73786 function(e) {
73787 var state = tile.getState();
73788 if (state == ol.TileState.LOADED ||
73789 state == ol.TileState.ERROR ||
73790 state == ol.TileState.EMPTY) {
73791 ol.events.unlistenByKey(sourceListenKey);
73792 leftToLoad--;
73793 if (leftToLoad === 0) {
73794 this.unlistenSources_();
73795 this.reproject_();
73796 }
73797 }
73798 }, this);
73799 this.sourcesListenerKeys_.push(sourceListenKey);
73800 }
73801 }, this);
73802
73803 this.sourceTiles_.forEach(function(tile, i, arr) {
73804 var state = tile.getState();
73805 if (state == ol.TileState.IDLE) {
73806 tile.load();
73807 }
73808 });
73809
73810 if (leftToLoad === 0) {
73811 setTimeout(this.reproject_.bind(this), 0);
73812 }
73813 }
73814};
73815
73816
73817/**
73818 * @private
73819 */
73820ol.reproj.Tile.prototype.unlistenSources_ = function() {
73821 this.sourcesListenerKeys_.forEach(ol.events.unlistenByKey);
73822 this.sourcesListenerKeys_ = null;
73823};
73824
73825goog.provide('ol.TileUrlFunction');
73826
73827goog.require('ol.asserts');
73828goog.require('ol.math');
73829goog.require('ol.tilecoord');
73830
73831
73832/**
73833 * @param {string} template Template.
73834 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
73835 * @return {ol.TileUrlFunctionType} Tile URL function.
73836 */
73837ol.TileUrlFunction.createFromTemplate = function(template, tileGrid) {
73838 var zRegEx = /\{z\}/g;
73839 var xRegEx = /\{x\}/g;
73840 var yRegEx = /\{y\}/g;
73841 var dashYRegEx = /\{-y\}/g;
73842 return (
73843 /**
73844 * @param {ol.TileCoord} tileCoord Tile Coordinate.
73845 * @param {number} pixelRatio Pixel ratio.
73846 * @param {ol.proj.Projection} projection Projection.
73847 * @return {string|undefined} Tile URL.
73848 */
73849 function(tileCoord, pixelRatio, projection) {
73850 if (!tileCoord) {
73851 return undefined;
73852 } else {
73853 return template.replace(zRegEx, tileCoord[0].toString())
73854 .replace(xRegEx, tileCoord[1].toString())
73855 .replace(yRegEx, function() {
73856 var y = -tileCoord[2] - 1;
73857 return y.toString();
73858 })
73859 .replace(dashYRegEx, function() {
73860 var z = tileCoord[0];
73861 var range = tileGrid.getFullTileRange(z);
73862 ol.asserts.assert(range, 55); // The {-y} placeholder requires a tile grid with extent
73863 var y = range.getHeight() + tileCoord[2];
73864 return y.toString();
73865 });
73866 }
73867 });
73868};
73869
73870
73871/**
73872 * @param {Array.<string>} templates Templates.
73873 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
73874 * @return {ol.TileUrlFunctionType} Tile URL function.
73875 */
73876ol.TileUrlFunction.createFromTemplates = function(templates, tileGrid) {
73877 var len = templates.length;
73878 var tileUrlFunctions = new Array(len);
73879 for (var i = 0; i < len; ++i) {
73880 tileUrlFunctions[i] = ol.TileUrlFunction.createFromTemplate(
73881 templates[i], tileGrid);
73882 }
73883 return ol.TileUrlFunction.createFromTileUrlFunctions(tileUrlFunctions);
73884};
73885
73886
73887/**
73888 * @param {Array.<ol.TileUrlFunctionType>} tileUrlFunctions Tile URL Functions.
73889 * @return {ol.TileUrlFunctionType} Tile URL function.
73890 */
73891ol.TileUrlFunction.createFromTileUrlFunctions = function(tileUrlFunctions) {
73892 if (tileUrlFunctions.length === 1) {
73893 return tileUrlFunctions[0];
73894 }
73895 return (
73896 /**
73897 * @param {ol.TileCoord} tileCoord Tile Coordinate.
73898 * @param {number} pixelRatio Pixel ratio.
73899 * @param {ol.proj.Projection} projection Projection.
73900 * @return {string|undefined} Tile URL.
73901 */
73902 function(tileCoord, pixelRatio, projection) {
73903 if (!tileCoord) {
73904 return undefined;
73905 } else {
73906 var h = ol.tilecoord.hash(tileCoord);
73907 var index = ol.math.modulo(h, tileUrlFunctions.length);
73908 return tileUrlFunctions[index](tileCoord, pixelRatio, projection);
73909 }
73910 });
73911};
73912
73913
73914/**
73915 * @param {ol.TileCoord} tileCoord Tile coordinate.
73916 * @param {number} pixelRatio Pixel ratio.
73917 * @param {ol.proj.Projection} projection Projection.
73918 * @return {string|undefined} Tile URL.
73919 */
73920ol.TileUrlFunction.nullTileUrlFunction = function(tileCoord, pixelRatio, projection) {
73921 return undefined;
73922};
73923
73924
73925/**
73926 * @param {string} url URL.
73927 * @return {Array.<string>} Array of urls.
73928 */
73929ol.TileUrlFunction.expandUrl = function(url) {
73930 var urls = [];
73931 var match = /\{([a-z])-([a-z])\}/.exec(url);
73932 if (match) {
73933 // char range
73934 var startCharCode = match[1].charCodeAt(0);
73935 var stopCharCode = match[2].charCodeAt(0);
73936 var charCode;
73937 for (charCode = startCharCode; charCode <= stopCharCode; ++charCode) {
73938 urls.push(url.replace(match[0], String.fromCharCode(charCode)));
73939 }
73940 return urls;
73941 }
73942 match = match = /\{(\d+)-(\d+)\}/.exec(url);
73943 if (match) {
73944 // number range
73945 var stop = parseInt(match[2], 10);
73946 for (var i = parseInt(match[1], 10); i <= stop; i++) {
73947 urls.push(url.replace(match[0], i.toString()));
73948 }
73949 return urls;
73950 }
73951 urls.push(url);
73952 return urls;
73953};
73954
73955goog.provide('ol.TileCache');
73956
73957goog.require('ol');
73958goog.require('ol.structs.LRUCache');
73959
73960
73961/**
73962 * @constructor
73963 * @extends {ol.structs.LRUCache.<ol.Tile>}
73964 * @param {number=} opt_highWaterMark High water mark.
73965 * @struct
73966 */
73967ol.TileCache = function(opt_highWaterMark) {
73968
73969 ol.structs.LRUCache.call(this);
73970
73971 /**
73972 * @type {number}
73973 */
73974 this.highWaterMark = opt_highWaterMark !== undefined ? opt_highWaterMark : 2048;
73975
73976};
73977ol.inherits(ol.TileCache, ol.structs.LRUCache);
73978
73979
73980/**
73981 * @return {boolean} Can expire cache.
73982 */
73983ol.TileCache.prototype.canExpireCache = function() {
73984 return this.getCount() > this.highWaterMark;
73985};
73986
73987
73988/**
73989 * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
73990 */
73991ol.TileCache.prototype.expireCache = function(usedTiles) {
73992 var tile, zKey;
73993 while (this.canExpireCache()) {
73994 tile = this.peekLast();
73995 zKey = tile.tileCoord[0].toString();
73996 if (zKey in usedTiles && usedTiles[zKey].contains(tile.tileCoord)) {
73997 break;
73998 } else {
73999 this.pop().dispose();
74000 }
74001 }
74002};
74003
74004goog.provide('ol.source.Tile');
74005
74006goog.require('ol');
74007goog.require('ol.TileCache');
74008goog.require('ol.TileState');
74009goog.require('ol.events.Event');
74010goog.require('ol.proj');
74011goog.require('ol.size');
74012goog.require('ol.source.Source');
74013goog.require('ol.tilecoord');
74014goog.require('ol.tilegrid');
74015
74016
74017/**
74018 * @classdesc
74019 * Abstract base class; normally only used for creating subclasses and not
74020 * instantiated in apps.
74021 * Base class for sources providing images divided into a tile grid.
74022 *
74023 * @constructor
74024 * @abstract
74025 * @extends {ol.source.Source}
74026 * @param {ol.SourceTileOptions} options Tile source options.
74027 * @api
74028 */
74029ol.source.Tile = function(options) {
74030
74031 ol.source.Source.call(this, {
74032 attributions: options.attributions,
74033 extent: options.extent,
74034 logo: options.logo,
74035 projection: options.projection,
74036 state: options.state,
74037 wrapX: options.wrapX
74038 });
74039
74040 /**
74041 * @private
74042 * @type {boolean}
74043 */
74044 this.opaque_ = options.opaque !== undefined ? options.opaque : false;
74045
74046 /**
74047 * @private
74048 * @type {number}
74049 */
74050 this.tilePixelRatio_ = options.tilePixelRatio !== undefined ?
74051 options.tilePixelRatio : 1;
74052
74053 /**
74054 * @protected
74055 * @type {ol.tilegrid.TileGrid}
74056 */
74057 this.tileGrid = options.tileGrid !== undefined ? options.tileGrid : null;
74058
74059 /**
74060 * @protected
74061 * @type {ol.TileCache}
74062 */
74063 this.tileCache = new ol.TileCache(options.cacheSize);
74064
74065 /**
74066 * @protected
74067 * @type {ol.Size}
74068 */
74069 this.tmpSize = [0, 0];
74070
74071 /**
74072 * @private
74073 * @type {string}
74074 */
74075 this.key_ = '';
74076
74077};
74078ol.inherits(ol.source.Tile, ol.source.Source);
74079
74080
74081/**
74082 * @return {boolean} Can expire cache.
74083 */
74084ol.source.Tile.prototype.canExpireCache = function() {
74085 return this.tileCache.canExpireCache();
74086};
74087
74088
74089/**
74090 * @param {ol.proj.Projection} projection Projection.
74091 * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
74092 */
74093ol.source.Tile.prototype.expireCache = function(projection, usedTiles) {
74094 var tileCache = this.getTileCacheForProjection(projection);
74095 if (tileCache) {
74096 tileCache.expireCache(usedTiles);
74097 }
74098};
74099
74100
74101/**
74102 * @param {ol.proj.Projection} projection Projection.
74103 * @param {number} z Zoom level.
74104 * @param {ol.TileRange} tileRange Tile range.
74105 * @param {function(ol.Tile):(boolean|undefined)} callback Called with each
74106 * loaded tile. If the callback returns `false`, the tile will not be
74107 * considered loaded.
74108 * @return {boolean} The tile range is fully covered with loaded tiles.
74109 */
74110ol.source.Tile.prototype.forEachLoadedTile = function(projection, z, tileRange, callback) {
74111 var tileCache = this.getTileCacheForProjection(projection);
74112 if (!tileCache) {
74113 return false;
74114 }
74115
74116 var covered = true;
74117 var tile, tileCoordKey, loaded;
74118 for (var x = tileRange.minX; x <= tileRange.maxX; ++x) {
74119 for (var y = tileRange.minY; y <= tileRange.maxY; ++y) {
74120 tileCoordKey = this.getKeyZXY(z, x, y);
74121 loaded = false;
74122 if (tileCache.containsKey(tileCoordKey)) {
74123 tile = /** @type {!ol.Tile} */ (tileCache.get(tileCoordKey));
74124 loaded = tile.getState() === ol.TileState.LOADED;
74125 if (loaded) {
74126 loaded = (callback(tile) !== false);
74127 }
74128 }
74129 if (!loaded) {
74130 covered = false;
74131 }
74132 }
74133 }
74134 return covered;
74135};
74136
74137
74138/**
74139 * @param {ol.proj.Projection} projection Projection.
74140 * @return {number} Gutter.
74141 */
74142ol.source.Tile.prototype.getGutter = function(projection) {
74143 return 0;
74144};
74145
74146
74147/**
74148 * Return the key to be used for all tiles in the source.
74149 * @return {string} The key for all tiles.
74150 * @protected
74151 */
74152ol.source.Tile.prototype.getKey = function() {
74153 return this.key_;
74154};
74155
74156
74157/**
74158 * Set the value to be used as the key for all tiles in the source.
74159 * @param {string} key The key for tiles.
74160 * @protected
74161 */
74162ol.source.Tile.prototype.setKey = function(key) {
74163 if (this.key_ !== key) {
74164 this.key_ = key;
74165 this.changed();
74166 }
74167};
74168
74169
74170/**
74171 * @param {number} z Z.
74172 * @param {number} x X.
74173 * @param {number} y Y.
74174 * @return {string} Key.
74175 * @protected
74176 */
74177ol.source.Tile.prototype.getKeyZXY = ol.tilecoord.getKeyZXY;
74178
74179
74180/**
74181 * @param {ol.proj.Projection} projection Projection.
74182 * @return {boolean} Opaque.
74183 */
74184ol.source.Tile.prototype.getOpaque = function(projection) {
74185 return this.opaque_;
74186};
74187
74188
74189/**
74190 * @inheritDoc
74191 */
74192ol.source.Tile.prototype.getResolutions = function() {
74193 return this.tileGrid.getResolutions();
74194};
74195
74196
74197/**
74198 * @abstract
74199 * @param {number} z Tile coordinate z.
74200 * @param {number} x Tile coordinate x.
74201 * @param {number} y Tile coordinate y.
74202 * @param {number} pixelRatio Pixel ratio.
74203 * @param {ol.proj.Projection} projection Projection.
74204 * @return {!ol.Tile} Tile.
74205 */
74206ol.source.Tile.prototype.getTile = function(z, x, y, pixelRatio, projection) {};
74207
74208
74209/**
74210 * Return the tile grid of the tile source.
74211 * @return {ol.tilegrid.TileGrid} Tile grid.
74212 * @api
74213 */
74214ol.source.Tile.prototype.getTileGrid = function() {
74215 return this.tileGrid;
74216};
74217
74218
74219/**
74220 * @param {ol.proj.Projection} projection Projection.
74221 * @return {!ol.tilegrid.TileGrid} Tile grid.
74222 */
74223ol.source.Tile.prototype.getTileGridForProjection = function(projection) {
74224 if (!this.tileGrid) {
74225 return ol.tilegrid.getForProjection(projection);
74226 } else {
74227 return this.tileGrid;
74228 }
74229};
74230
74231
74232/**
74233 * @param {ol.proj.Projection} projection Projection.
74234 * @return {ol.TileCache} Tile cache.
74235 * @protected
74236 */
74237ol.source.Tile.prototype.getTileCacheForProjection = function(projection) {
74238 var thisProj = this.getProjection();
74239 if (thisProj && !ol.proj.equivalent(thisProj, projection)) {
74240 return null;
74241 } else {
74242 return this.tileCache;
74243 }
74244};
74245
74246
74247/**
74248 * Get the tile pixel ratio for this source. Subclasses may override this
74249 * method, which is meant to return a supported pixel ratio that matches the
74250 * provided `pixelRatio` as close as possible.
74251 * @param {number} pixelRatio Pixel ratio.
74252 * @return {number} Tile pixel ratio.
74253 */
74254ol.source.Tile.prototype.getTilePixelRatio = function(pixelRatio) {
74255 return this.tilePixelRatio_;
74256};
74257
74258
74259/**
74260 * @param {number} z Z.
74261 * @param {number} pixelRatio Pixel ratio.
74262 * @param {ol.proj.Projection} projection Projection.
74263 * @return {ol.Size} Tile size.
74264 */
74265ol.source.Tile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
74266 var tileGrid = this.getTileGridForProjection(projection);
74267 var tilePixelRatio = this.getTilePixelRatio(pixelRatio);
74268 var tileSize = ol.size.toSize(tileGrid.getTileSize(z), this.tmpSize);
74269 if (tilePixelRatio == 1) {
74270 return tileSize;
74271 } else {
74272 return ol.size.scale(tileSize, tilePixelRatio, this.tmpSize);
74273 }
74274};
74275
74276
74277/**
74278 * Returns a tile coordinate wrapped around the x-axis. When the tile coordinate
74279 * is outside the resolution and extent range of the tile grid, `null` will be
74280 * returned.
74281 * @param {ol.TileCoord} tileCoord Tile coordinate.
74282 * @param {ol.proj.Projection=} opt_projection Projection.
74283 * @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or
74284 * null if no tile URL should be created for the passed `tileCoord`.
74285 */
74286ol.source.Tile.prototype.getTileCoordForTileUrlFunction = function(tileCoord, opt_projection) {
74287 var projection = opt_projection !== undefined ?
74288 opt_projection : this.getProjection();
74289 var tileGrid = this.getTileGridForProjection(projection);
74290 if (this.getWrapX() && projection.isGlobal()) {
74291 tileCoord = ol.tilegrid.wrapX(tileGrid, tileCoord, projection);
74292 }
74293 return ol.tilecoord.withinExtentAndZ(tileCoord, tileGrid) ? tileCoord : null;
74294};
74295
74296
74297/**
74298 * @inheritDoc
74299 */
74300ol.source.Tile.prototype.refresh = function() {
74301 this.tileCache.clear();
74302 this.changed();
74303};
74304
74305
74306/**
74307 * Marks a tile coord as being used, without triggering a load.
74308 * @param {number} z Tile coordinate z.
74309 * @param {number} x Tile coordinate x.
74310 * @param {number} y Tile coordinate y.
74311 * @param {ol.proj.Projection} projection Projection.
74312 */
74313ol.source.Tile.prototype.useTile = ol.nullFunction;
74314
74315
74316/**
74317 * @classdesc
74318 * Events emitted by {@link ol.source.Tile} instances are instances of this
74319 * type.
74320 *
74321 * @constructor
74322 * @extends {ol.events.Event}
74323 * @implements {oli.source.Tile.Event}
74324 * @param {string} type Type.
74325 * @param {ol.Tile} tile The tile.
74326 */
74327ol.source.Tile.Event = function(type, tile) {
74328
74329 ol.events.Event.call(this, type);
74330
74331 /**
74332 * The tile related to the event.
74333 * @type {ol.Tile}
74334 * @api
74335 */
74336 this.tile = tile;
74337
74338};
74339ol.inherits(ol.source.Tile.Event, ol.events.Event);
74340
74341goog.provide('ol.source.TileEventType');
74342
74343/**
74344 * @enum {string}
74345 */
74346ol.source.TileEventType = {
74347
74348 /**
74349 * Triggered when a tile starts loading.
74350 * @event ol.source.Tile.Event#tileloadstart
74351 * @api
74352 */
74353 TILELOADSTART: 'tileloadstart',
74354
74355 /**
74356 * Triggered when a tile finishes loading.
74357 * @event ol.source.Tile.Event#tileloadend
74358 * @api
74359 */
74360 TILELOADEND: 'tileloadend',
74361
74362 /**
74363 * Triggered if tile loading results in an error.
74364 * @event ol.source.Tile.Event#tileloaderror
74365 * @api
74366 */
74367 TILELOADERROR: 'tileloaderror'
74368
74369};
74370
74371goog.provide('ol.source.UrlTile');
74372
74373goog.require('ol');
74374goog.require('ol.TileState');
74375goog.require('ol.TileUrlFunction');
74376goog.require('ol.source.Tile');
74377goog.require('ol.source.TileEventType');
74378
74379
74380/**
74381 * @classdesc
74382 * Base class for sources providing tiles divided into a tile grid over http.
74383 *
74384 * @constructor
74385 * @abstract
74386 * @fires ol.source.Tile.Event
74387 * @extends {ol.source.Tile}
74388 * @param {ol.SourceUrlTileOptions} options Image tile options.
74389 */
74390ol.source.UrlTile = function(options) {
74391
74392 ol.source.Tile.call(this, {
74393 attributions: options.attributions,
74394 cacheSize: options.cacheSize,
74395 extent: options.extent,
74396 logo: options.logo,
74397 opaque: options.opaque,
74398 projection: options.projection,
74399 state: options.state,
74400 tileGrid: options.tileGrid,
74401 tilePixelRatio: options.tilePixelRatio,
74402 wrapX: options.wrapX
74403 });
74404
74405 /**
74406 * @protected
74407 * @type {ol.TileLoadFunctionType}
74408 */
74409 this.tileLoadFunction = options.tileLoadFunction;
74410
74411 /**
74412 * @protected
74413 * @type {ol.TileUrlFunctionType}
74414 */
74415 this.tileUrlFunction = this.fixedTileUrlFunction ?
74416 this.fixedTileUrlFunction.bind(this) :
74417 ol.TileUrlFunction.nullTileUrlFunction;
74418
74419 /**
74420 * @protected
74421 * @type {!Array.<string>|null}
74422 */
74423 this.urls = null;
74424
74425 if (options.urls) {
74426 this.setUrls(options.urls);
74427 } else if (options.url) {
74428 this.setUrl(options.url);
74429 }
74430 if (options.tileUrlFunction) {
74431 this.setTileUrlFunction(options.tileUrlFunction);
74432 }
74433
74434};
74435ol.inherits(ol.source.UrlTile, ol.source.Tile);
74436
74437
74438/**
74439 * @type {ol.TileUrlFunctionType|undefined}
74440 * @protected
74441 */
74442ol.source.UrlTile.prototype.fixedTileUrlFunction;
74443
74444/**
74445 * Return the tile load function of the source.
74446 * @return {ol.TileLoadFunctionType} TileLoadFunction
74447 * @api
74448 */
74449ol.source.UrlTile.prototype.getTileLoadFunction = function() {
74450 return this.tileLoadFunction;
74451};
74452
74453
74454/**
74455 * Return the tile URL function of the source.
74456 * @return {ol.TileUrlFunctionType} TileUrlFunction
74457 * @api
74458 */
74459ol.source.UrlTile.prototype.getTileUrlFunction = function() {
74460 return this.tileUrlFunction;
74461};
74462
74463
74464/**
74465 * Return the URLs used for this source.
74466 * When a tileUrlFunction is used instead of url or urls,
74467 * null will be returned.
74468 * @return {!Array.<string>|null} URLs.
74469 * @api
74470 */
74471ol.source.UrlTile.prototype.getUrls = function() {
74472 return this.urls;
74473};
74474
74475
74476/**
74477 * Handle tile change events.
74478 * @param {ol.events.Event} event Event.
74479 * @protected
74480 */
74481ol.source.UrlTile.prototype.handleTileChange = function(event) {
74482 var tile = /** @type {ol.Tile} */ (event.target);
74483 switch (tile.getState()) {
74484 case ol.TileState.LOADING:
74485 this.dispatchEvent(
74486 new ol.source.Tile.Event(ol.source.TileEventType.TILELOADSTART, tile));
74487 break;
74488 case ol.TileState.LOADED:
74489 this.dispatchEvent(
74490 new ol.source.Tile.Event(ol.source.TileEventType.TILELOADEND, tile));
74491 break;
74492 case ol.TileState.ERROR:
74493 this.dispatchEvent(
74494 new ol.source.Tile.Event(ol.source.TileEventType.TILELOADERROR, tile));
74495 break;
74496 default:
74497 // pass
74498 }
74499};
74500
74501
74502/**
74503 * Set the tile load function of the source.
74504 * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
74505 * @api
74506 */
74507ol.source.UrlTile.prototype.setTileLoadFunction = function(tileLoadFunction) {
74508 this.tileCache.clear();
74509 this.tileLoadFunction = tileLoadFunction;
74510 this.changed();
74511};
74512
74513
74514/**
74515 * Set the tile URL function of the source.
74516 * @param {ol.TileUrlFunctionType} tileUrlFunction Tile URL function.
74517 * @param {string=} opt_key Optional new tile key for the source.
74518 * @api
74519 */
74520ol.source.UrlTile.prototype.setTileUrlFunction = function(tileUrlFunction, opt_key) {
74521 this.tileUrlFunction = tileUrlFunction;
74522 if (typeof opt_key !== 'undefined') {
74523 this.setKey(opt_key);
74524 } else {
74525 this.changed();
74526 }
74527};
74528
74529
74530/**
74531 * Set the URL to use for requests.
74532 * @param {string} url URL.
74533 * @api
74534 */
74535ol.source.UrlTile.prototype.setUrl = function(url) {
74536 var urls = this.urls = ol.TileUrlFunction.expandUrl(url);
74537 this.setTileUrlFunction(this.fixedTileUrlFunction ?
74538 this.fixedTileUrlFunction.bind(this) :
74539 ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), url);
74540};
74541
74542
74543/**
74544 * Set the URLs to use for requests.
74545 * @param {Array.<string>} urls URLs.
74546 * @api
74547 */
74548ol.source.UrlTile.prototype.setUrls = function(urls) {
74549 this.urls = urls;
74550 var key = urls.join('\n');
74551 this.setTileUrlFunction(this.fixedTileUrlFunction ?
74552 this.fixedTileUrlFunction.bind(this) :
74553 ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), key);
74554};
74555
74556
74557/**
74558 * @inheritDoc
74559 */
74560ol.source.UrlTile.prototype.useTile = function(z, x, y) {
74561 var tileCoordKey = this.getKeyZXY(z, x, y);
74562 if (this.tileCache.containsKey(tileCoordKey)) {
74563 this.tileCache.get(tileCoordKey);
74564 }
74565};
74566
74567goog.provide('ol.source.TileImage');
74568
74569goog.require('ol');
74570goog.require('ol.ImageTile');
74571goog.require('ol.TileCache');
74572goog.require('ol.TileState');
74573goog.require('ol.events');
74574goog.require('ol.events.EventType');
74575goog.require('ol.proj');
74576goog.require('ol.reproj.Tile');
74577goog.require('ol.source.UrlTile');
74578goog.require('ol.tilegrid');
74579
74580
74581/**
74582 * @classdesc
74583 * Base class for sources providing images divided into a tile grid.
74584 *
74585 * @constructor
74586 * @fires ol.source.Tile.Event
74587 * @extends {ol.source.UrlTile}
74588 * @param {olx.source.TileImageOptions} options Image tile options.
74589 * @api
74590 */
74591ol.source.TileImage = function(options) {
74592
74593 ol.source.UrlTile.call(this, {
74594 attributions: options.attributions,
74595 cacheSize: options.cacheSize,
74596 extent: options.extent,
74597 logo: options.logo,
74598 opaque: options.opaque,
74599 projection: options.projection,
74600 state: options.state,
74601 tileGrid: options.tileGrid,
74602 tileLoadFunction: options.tileLoadFunction ?
74603 options.tileLoadFunction : ol.source.TileImage.defaultTileLoadFunction,
74604 tilePixelRatio: options.tilePixelRatio,
74605 tileUrlFunction: options.tileUrlFunction,
74606 url: options.url,
74607 urls: options.urls,
74608 wrapX: options.wrapX
74609 });
74610
74611 /**
74612 * @protected
74613 * @type {?string}
74614 */
74615 this.crossOrigin =
74616 options.crossOrigin !== undefined ? options.crossOrigin : null;
74617
74618 /**
74619 * @protected
74620 * @type {function(new: ol.ImageTile, ol.TileCoord, ol.TileState, string,
74621 * ?string, ol.TileLoadFunctionType)}
74622 */
74623 this.tileClass = options.tileClass !== undefined ?
74624 options.tileClass : ol.ImageTile;
74625
74626 /**
74627 * @protected
74628 * @type {Object.<string, ol.TileCache>}
74629 */
74630 this.tileCacheForProjection = {};
74631
74632 /**
74633 * @protected
74634 * @type {Object.<string, ol.tilegrid.TileGrid>}
74635 */
74636 this.tileGridForProjection = {};
74637
74638 /**
74639 * @private
74640 * @type {number|undefined}
74641 */
74642 this.reprojectionErrorThreshold_ = options.reprojectionErrorThreshold;
74643
74644 /**
74645 * @private
74646 * @type {boolean}
74647 */
74648 this.renderReprojectionEdges_ = false;
74649};
74650ol.inherits(ol.source.TileImage, ol.source.UrlTile);
74651
74652
74653/**
74654 * @inheritDoc
74655 */
74656ol.source.TileImage.prototype.canExpireCache = function() {
74657 if (!ol.ENABLE_RASTER_REPROJECTION) {
74658 return ol.source.UrlTile.prototype.canExpireCache.call(this);
74659 }
74660 if (this.tileCache.canExpireCache()) {
74661 return true;
74662 } else {
74663 for (var key in this.tileCacheForProjection) {
74664 if (this.tileCacheForProjection[key].canExpireCache()) {
74665 return true;
74666 }
74667 }
74668 }
74669 return false;
74670};
74671
74672
74673/**
74674 * @inheritDoc
74675 */
74676ol.source.TileImage.prototype.expireCache = function(projection, usedTiles) {
74677 if (!ol.ENABLE_RASTER_REPROJECTION) {
74678 ol.source.UrlTile.prototype.expireCache.call(this, projection, usedTiles);
74679 return;
74680 }
74681 var usedTileCache = this.getTileCacheForProjection(projection);
74682
74683 this.tileCache.expireCache(this.tileCache == usedTileCache ? usedTiles : {});
74684 for (var id in this.tileCacheForProjection) {
74685 var tileCache = this.tileCacheForProjection[id];
74686 tileCache.expireCache(tileCache == usedTileCache ? usedTiles : {});
74687 }
74688};
74689
74690
74691/**
74692 * @inheritDoc
74693 */
74694ol.source.TileImage.prototype.getGutter = function(projection) {
74695 if (ol.ENABLE_RASTER_REPROJECTION &&
74696 this.getProjection() && projection &&
74697 !ol.proj.equivalent(this.getProjection(), projection)) {
74698 return 0;
74699 } else {
74700 return this.getGutterInternal();
74701 }
74702};
74703
74704
74705/**
74706 * @protected
74707 * @return {number} Gutter.
74708 */
74709ol.source.TileImage.prototype.getGutterInternal = function() {
74710 return 0;
74711};
74712
74713
74714/**
74715 * @inheritDoc
74716 */
74717ol.source.TileImage.prototype.getOpaque = function(projection) {
74718 if (ol.ENABLE_RASTER_REPROJECTION &&
74719 this.getProjection() && projection &&
74720 !ol.proj.equivalent(this.getProjection(), projection)) {
74721 return false;
74722 } else {
74723 return ol.source.UrlTile.prototype.getOpaque.call(this, projection);
74724 }
74725};
74726
74727
74728/**
74729 * @inheritDoc
74730 */
74731ol.source.TileImage.prototype.getTileGridForProjection = function(projection) {
74732 if (!ol.ENABLE_RASTER_REPROJECTION) {
74733 return ol.source.UrlTile.prototype.getTileGridForProjection.call(this, projection);
74734 }
74735 var thisProj = this.getProjection();
74736 if (this.tileGrid &&
74737 (!thisProj || ol.proj.equivalent(thisProj, projection))) {
74738 return this.tileGrid;
74739 } else {
74740 var projKey = ol.getUid(projection).toString();
74741 if (!(projKey in this.tileGridForProjection)) {
74742 this.tileGridForProjection[projKey] =
74743 ol.tilegrid.getForProjection(projection);
74744 }
74745 return /** @type {!ol.tilegrid.TileGrid} */ (this.tileGridForProjection[projKey]);
74746 }
74747};
74748
74749
74750/**
74751 * @inheritDoc
74752 */
74753ol.source.TileImage.prototype.getTileCacheForProjection = function(projection) {
74754 if (!ol.ENABLE_RASTER_REPROJECTION) {
74755 return ol.source.UrlTile.prototype.getTileCacheForProjection.call(this, projection);
74756 }
74757 var thisProj = this.getProjection();
74758 if (!thisProj || ol.proj.equivalent(thisProj, projection)) {
74759 return this.tileCache;
74760 } else {
74761 var projKey = ol.getUid(projection).toString();
74762 if (!(projKey in this.tileCacheForProjection)) {
74763 this.tileCacheForProjection[projKey] = new ol.TileCache(this.tileCache.highWaterMark);
74764 }
74765 return this.tileCacheForProjection[projKey];
74766 }
74767};
74768
74769
74770/**
74771 * @param {number} z Tile coordinate z.
74772 * @param {number} x Tile coordinate x.
74773 * @param {number} y Tile coordinate y.
74774 * @param {number} pixelRatio Pixel ratio.
74775 * @param {ol.proj.Projection} projection Projection.
74776 * @param {string} key The key set on the tile.
74777 * @return {!ol.Tile} Tile.
74778 * @private
74779 */
74780ol.source.TileImage.prototype.createTile_ = function(z, x, y, pixelRatio, projection, key) {
74781 var tileCoord = [z, x, y];
74782 var urlTileCoord = this.getTileCoordForTileUrlFunction(
74783 tileCoord, projection);
74784 var tileUrl = urlTileCoord ?
74785 this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
74786 var tile = new this.tileClass(
74787 tileCoord,
74788 tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
74789 tileUrl !== undefined ? tileUrl : '',
74790 this.crossOrigin,
74791 this.tileLoadFunction);
74792 tile.key = key;
74793 ol.events.listen(tile, ol.events.EventType.CHANGE,
74794 this.handleTileChange, this);
74795 return tile;
74796};
74797
74798
74799/**
74800 * @inheritDoc
74801 */
74802ol.source.TileImage.prototype.getTile = function(z, x, y, pixelRatio, projection) {
74803 if (!ol.ENABLE_RASTER_REPROJECTION ||
74804 !this.getProjection() ||
74805 !projection ||
74806 ol.proj.equivalent(this.getProjection(), projection)) {
74807 return this.getTileInternal(z, x, y, pixelRatio, /** @type {!ol.proj.Projection} */ (projection));
74808 } else {
74809 var cache = this.getTileCacheForProjection(projection);
74810 var tileCoord = [z, x, y];
74811 var tile;
74812 var tileCoordKey = this.getKeyZXY.apply(this, tileCoord);
74813 if (cache.containsKey(tileCoordKey)) {
74814 tile = /** @type {!ol.Tile} */ (cache.get(tileCoordKey));
74815 }
74816 var key = this.getKey();
74817 if (tile && tile.key == key) {
74818 return tile;
74819 } else {
74820 var sourceProjection = /** @type {!ol.proj.Projection} */ (this.getProjection());
74821 var sourceTileGrid = this.getTileGridForProjection(sourceProjection);
74822 var targetTileGrid = this.getTileGridForProjection(projection);
74823 var wrappedTileCoord =
74824 this.getTileCoordForTileUrlFunction(tileCoord, projection);
74825 var newTile = new ol.reproj.Tile(
74826 sourceProjection, sourceTileGrid,
74827 projection, targetTileGrid,
74828 tileCoord, wrappedTileCoord, this.getTilePixelRatio(pixelRatio),
74829 this.getGutterInternal(),
74830 function(z, x, y, pixelRatio) {
74831 return this.getTileInternal(z, x, y, pixelRatio, sourceProjection);
74832 }.bind(this), this.reprojectionErrorThreshold_,
74833 this.renderReprojectionEdges_);
74834 newTile.key = key;
74835
74836 if (tile) {
74837 newTile.interimTile = tile;
74838 newTile.refreshInterimChain();
74839 cache.replace(tileCoordKey, newTile);
74840 } else {
74841 cache.set(tileCoordKey, newTile);
74842 }
74843 return newTile;
74844 }
74845 }
74846};
74847
74848
74849/**
74850 * @param {number} z Tile coordinate z.
74851 * @param {number} x Tile coordinate x.
74852 * @param {number} y Tile coordinate y.
74853 * @param {number} pixelRatio Pixel ratio.
74854 * @param {!ol.proj.Projection} projection Projection.
74855 * @return {!ol.Tile} Tile.
74856 * @protected
74857 */
74858ol.source.TileImage.prototype.getTileInternal = function(z, x, y, pixelRatio, projection) {
74859 var tile = null;
74860 var tileCoordKey = this.getKeyZXY(z, x, y);
74861 var key = this.getKey();
74862 if (!this.tileCache.containsKey(tileCoordKey)) {
74863 tile = this.createTile_(z, x, y, pixelRatio, projection, key);
74864 this.tileCache.set(tileCoordKey, tile);
74865 } else {
74866 tile = this.tileCache.get(tileCoordKey);
74867 if (tile.key != key) {
74868 // The source's params changed. If the tile has an interim tile and if we
74869 // can use it then we use it. Otherwise we create a new tile. In both
74870 // cases we attempt to assign an interim tile to the new tile.
74871 var interimTile = tile;
74872 tile = this.createTile_(z, x, y, pixelRatio, projection, key);
74873
74874 //make the new tile the head of the list,
74875 if (interimTile.getState() == ol.TileState.IDLE) {
74876 //the old tile hasn't begun loading yet, and is now outdated, so we can simply discard it
74877 tile.interimTile = interimTile.interimTile;
74878 } else {
74879 tile.interimTile = interimTile;
74880 }
74881 tile.refreshInterimChain();
74882 this.tileCache.replace(tileCoordKey, tile);
74883 }
74884 }
74885 return tile;
74886};
74887
74888
74889/**
74890 * Sets whether to render reprojection edges or not (usually for debugging).
74891 * @param {boolean} render Render the edges.
74892 * @api
74893 */
74894ol.source.TileImage.prototype.setRenderReprojectionEdges = function(render) {
74895 if (!ol.ENABLE_RASTER_REPROJECTION ||
74896 this.renderReprojectionEdges_ == render) {
74897 return;
74898 }
74899 this.renderReprojectionEdges_ = render;
74900 for (var id in this.tileCacheForProjection) {
74901 this.tileCacheForProjection[id].clear();
74902 }
74903 this.changed();
74904};
74905
74906
74907/**
74908 * Sets the tile grid to use when reprojecting the tiles to the given
74909 * projection instead of the default tile grid for the projection.
74910 *
74911 * This can be useful when the default tile grid cannot be created
74912 * (e.g. projection has no extent defined) or
74913 * for optimization reasons (custom tile size, resolutions, ...).
74914 *
74915 * @param {ol.ProjectionLike} projection Projection.
74916 * @param {ol.tilegrid.TileGrid} tilegrid Tile grid to use for the projection.
74917 * @api
74918 */
74919ol.source.TileImage.prototype.setTileGridForProjection = function(projection, tilegrid) {
74920 if (ol.ENABLE_RASTER_REPROJECTION) {
74921 var proj = ol.proj.get(projection);
74922 if (proj) {
74923 var projKey = ol.getUid(proj).toString();
74924 if (!(projKey in this.tileGridForProjection)) {
74925 this.tileGridForProjection[projKey] = tilegrid;
74926 }
74927 }
74928 }
74929};
74930
74931
74932/**
74933 * @param {ol.ImageTile} imageTile Image tile.
74934 * @param {string} src Source.
74935 */
74936ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) {
74937 imageTile.getImage().src = src;
74938};
74939
74940goog.provide('ol.source.BingMaps');
74941
74942goog.require('ol');
74943goog.require('ol.Attribution');
74944goog.require('ol.TileUrlFunction');
74945goog.require('ol.extent');
74946goog.require('ol.net');
74947goog.require('ol.proj');
74948goog.require('ol.source.State');
74949goog.require('ol.source.TileImage');
74950goog.require('ol.tilecoord');
74951goog.require('ol.tilegrid');
74952
74953
74954/**
74955 * @classdesc
74956 * Layer source for Bing Maps tile data.
74957 *
74958 * @constructor
74959 * @extends {ol.source.TileImage}
74960 * @param {olx.source.BingMapsOptions} options Bing Maps options.
74961 * @api
74962 */
74963ol.source.BingMaps = function(options) {
74964
74965 /**
74966 * @private
74967 * @type {boolean}
74968 */
74969 this.hidpi_ = options.hidpi !== undefined ? options.hidpi : false;
74970
74971 ol.source.TileImage.call(this, {
74972 cacheSize: options.cacheSize,
74973 crossOrigin: 'anonymous',
74974 opaque: true,
74975 projection: ol.proj.get('EPSG:3857'),
74976 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
74977 state: ol.source.State.LOADING,
74978 tileLoadFunction: options.tileLoadFunction,
74979 tilePixelRatio: this.hidpi_ ? 2 : 1,
74980 wrapX: options.wrapX !== undefined ? options.wrapX : true
74981 });
74982
74983 /**
74984 * @private
74985 * @type {string}
74986 */
74987 this.culture_ = options.culture !== undefined ? options.culture : 'en-us';
74988
74989 /**
74990 * @private
74991 * @type {number}
74992 */
74993 this.maxZoom_ = options.maxZoom !== undefined ? options.maxZoom : -1;
74994
74995 /**
74996 * @private
74997 * @type {string}
74998 */
74999 this.apiKey_ = options.key;
75000
75001 /**
75002 * @private
75003 * @type {string}
75004 */
75005 this.imagerySet_ = options.imagerySet;
75006
75007 var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/' +
75008 this.imagerySet_ +
75009 '?uriScheme=https&include=ImageryProviders&key=' + this.apiKey_;
75010
75011 ol.net.jsonp(url, this.handleImageryMetadataResponse.bind(this), undefined,
75012 'jsonp');
75013
75014};
75015ol.inherits(ol.source.BingMaps, ol.source.TileImage);
75016
75017
75018/**
75019 * The attribution containing a link to the Microsoft® Bing™ Maps Platform APIs’
75020 * Terms Of Use.
75021 * @const
75022 * @type {ol.Attribution}
75023 * @api
75024 */
75025ol.source.BingMaps.TOS_ATTRIBUTION = new ol.Attribution({
75026 html: '<a class="ol-attribution-bing-tos" ' +
75027 'href="https://www.microsoft.com/maps/product/terms.html">' +
75028 'Terms of Use</a>'
75029});
75030
75031
75032/**
75033 * Get the api key used for this source.
75034 *
75035 * @return {string} The api key.
75036 * @api
75037 */
75038ol.source.BingMaps.prototype.getApiKey = function() {
75039 return this.apiKey_;
75040};
75041
75042
75043/**
75044 * Get the imagery set associated with this source.
75045 *
75046 * @return {string} The imagery set.
75047 * @api
75048 */
75049ol.source.BingMaps.prototype.getImagerySet = function() {
75050 return this.imagerySet_;
75051};
75052
75053
75054/**
75055 * @param {BingMapsImageryMetadataResponse} response Response.
75056 */
75057ol.source.BingMaps.prototype.handleImageryMetadataResponse = function(response) {
75058 if (response.statusCode != 200 ||
75059 response.statusDescription != 'OK' ||
75060 response.authenticationResultCode != 'ValidCredentials' ||
75061 response.resourceSets.length != 1 ||
75062 response.resourceSets[0].resources.length != 1) {
75063 this.setState(ol.source.State.ERROR);
75064 return;
75065 }
75066
75067 var brandLogoUri = response.brandLogoUri;
75068 if (brandLogoUri.indexOf('https') == -1) {
75069 brandLogoUri = brandLogoUri.replace('http', 'https');
75070 }
75071 //var copyright = response.copyright; // FIXME do we need to display this?
75072 var resource = response.resourceSets[0].resources[0];
75073 var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_;
75074
75075 var sourceProjection = this.getProjection();
75076 var extent = ol.tilegrid.extentFromProjection(sourceProjection);
75077 var tileSize = resource.imageWidth == resource.imageHeight ?
75078 resource.imageWidth : [resource.imageWidth, resource.imageHeight];
75079 var tileGrid = ol.tilegrid.createXYZ({
75080 extent: extent,
75081 minZoom: resource.zoomMin,
75082 maxZoom: maxZoom,
75083 tileSize: tileSize / (this.hidpi_ ? 2 : 1)
75084 });
75085 this.tileGrid = tileGrid;
75086
75087 var culture = this.culture_;
75088 var hidpi = this.hidpi_;
75089 this.tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(
75090 resource.imageUrlSubdomains.map(function(subdomain) {
75091 var quadKeyTileCoord = [0, 0, 0];
75092 var imageUrl = resource.imageUrl
75093 .replace('{subdomain}', subdomain)
75094 .replace('{culture}', culture);
75095 return (
75096 /**
75097 * @param {ol.TileCoord} tileCoord Tile coordinate.
75098 * @param {number} pixelRatio Pixel ratio.
75099 * @param {ol.proj.Projection} projection Projection.
75100 * @return {string|undefined} Tile URL.
75101 */
75102 function(tileCoord, pixelRatio, projection) {
75103 if (!tileCoord) {
75104 return undefined;
75105 } else {
75106 ol.tilecoord.createOrUpdate(tileCoord[0], tileCoord[1],
75107 -tileCoord[2] - 1, quadKeyTileCoord);
75108 var url = imageUrl;
75109 if (hidpi) {
75110 url += '&dpi=d1&device=mobile';
75111 }
75112 return url.replace('{quadkey}', ol.tilecoord.quadKey(
75113 quadKeyTileCoord));
75114 }
75115 });
75116 }));
75117
75118 if (resource.imageryProviders) {
75119 var transform = ol.proj.getTransformFromProjections(
75120 ol.proj.get('EPSG:4326'), this.getProjection());
75121
75122 var attributions = resource.imageryProviders.map(function(imageryProvider) {
75123 var html = imageryProvider.attribution;
75124 /** @type {Object.<string, Array.<ol.TileRange>>} */
75125 var tileRanges = {};
75126 imageryProvider.coverageAreas.forEach(function(coverageArea) {
75127 var minZ = coverageArea.zoomMin;
75128 var maxZ = Math.min(coverageArea.zoomMax, maxZoom);
75129 var bbox = coverageArea.bbox;
75130 var epsg4326Extent = [bbox[1], bbox[0], bbox[3], bbox[2]];
75131 var extent = ol.extent.applyTransform(epsg4326Extent, transform);
75132 var tileRange, z, zKey;
75133 for (z = minZ; z <= maxZ; ++z) {
75134 zKey = z.toString();
75135 tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
75136 if (zKey in tileRanges) {
75137 tileRanges[zKey].push(tileRange);
75138 } else {
75139 tileRanges[zKey] = [tileRange];
75140 }
75141 }
75142 });
75143 return new ol.Attribution({html: html, tileRanges: tileRanges});
75144 });
75145 attributions.push(ol.source.BingMaps.TOS_ATTRIBUTION);
75146 this.setAttributions(attributions);
75147 }
75148
75149 this.setLogo(brandLogoUri);
75150
75151 this.setState(ol.source.State.READY);
75152};
75153
75154goog.provide('ol.source.XYZ');
75155
75156goog.require('ol');
75157goog.require('ol.source.TileImage');
75158goog.require('ol.tilegrid');
75159
75160
75161/**
75162 * @classdesc
75163 * Layer source for tile data with URLs in a set XYZ format that are
75164 * defined in a URL template. By default, this follows the widely-used
75165 * Google grid where `x` 0 and `y` 0 are in the top left. Grids like
75166 * TMS where `x` 0 and `y` 0 are in the bottom left can be used by
75167 * using the `{-y}` placeholder in the URL template, so long as the
75168 * source does not have a custom tile grid. In this case,
75169 * {@link ol.source.TileImage} can be used with a `tileUrlFunction`
75170 * such as:
75171 *
75172 * tileUrlFunction: function(coordinate) {
75173 * return 'http://mapserver.com/' + coordinate[0] + '/' +
75174 * coordinate[1] + '/' + coordinate[2] + '.png';
75175 * }
75176 *
75177 *
75178 * @constructor
75179 * @extends {ol.source.TileImage}
75180 * @param {olx.source.XYZOptions=} opt_options XYZ options.
75181 * @api
75182 */
75183ol.source.XYZ = function(opt_options) {
75184 var options = opt_options || {};
75185 var projection = options.projection !== undefined ?
75186 options.projection : 'EPSG:3857';
75187
75188 var tileGrid = options.tileGrid !== undefined ? options.tileGrid :
75189 ol.tilegrid.createXYZ({
75190 extent: ol.tilegrid.extentFromProjection(projection),
75191 maxZoom: options.maxZoom,
75192 minZoom: options.minZoom,
75193 tileSize: options.tileSize
75194 });
75195
75196 ol.source.TileImage.call(this, {
75197 attributions: options.attributions,
75198 cacheSize: options.cacheSize,
75199 crossOrigin: options.crossOrigin,
75200 logo: options.logo,
75201 opaque: options.opaque,
75202 projection: projection,
75203 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
75204 tileGrid: tileGrid,
75205 tileLoadFunction: options.tileLoadFunction,
75206 tilePixelRatio: options.tilePixelRatio,
75207 tileUrlFunction: options.tileUrlFunction,
75208 url: options.url,
75209 urls: options.urls,
75210 wrapX: options.wrapX !== undefined ? options.wrapX : true
75211 });
75212
75213};
75214ol.inherits(ol.source.XYZ, ol.source.TileImage);
75215
75216goog.provide('ol.source.CartoDB');
75217
75218goog.require('ol');
75219goog.require('ol.obj');
75220goog.require('ol.source.State');
75221goog.require('ol.source.XYZ');
75222
75223
75224/**
75225 * @classdesc
75226 * Layer source for the CartoDB tiles.
75227 *
75228 * @constructor
75229 * @extends {ol.source.XYZ}
75230 * @param {olx.source.CartoDBOptions} options CartoDB options.
75231 * @api
75232 */
75233ol.source.CartoDB = function(options) {
75234
75235 /**
75236 * @type {string}
75237 * @private
75238 */
75239 this.account_ = options.account;
75240
75241 /**
75242 * @type {string}
75243 * @private
75244 */
75245 this.mapId_ = options.map || '';
75246
75247 /**
75248 * @type {!Object}
75249 * @private
75250 */
75251 this.config_ = options.config || {};
75252
75253 /**
75254 * @type {!Object.<string, CartoDBLayerInfo>}
75255 * @private
75256 */
75257 this.templateCache_ = {};
75258
75259 ol.source.XYZ.call(this, {
75260 attributions: options.attributions,
75261 cacheSize: options.cacheSize,
75262 crossOrigin: options.crossOrigin,
75263 logo: options.logo,
75264 maxZoom: options.maxZoom !== undefined ? options.maxZoom : 18,
75265 minZoom: options.minZoom,
75266 projection: options.projection,
75267 state: ol.source.State.LOADING,
75268 wrapX: options.wrapX
75269 });
75270 this.initializeMap_();
75271};
75272ol.inherits(ol.source.CartoDB, ol.source.XYZ);
75273
75274
75275/**
75276 * Returns the current config.
75277 * @return {!Object} The current configuration.
75278 * @api
75279 */
75280ol.source.CartoDB.prototype.getConfig = function() {
75281 return this.config_;
75282};
75283
75284
75285/**
75286 * Updates the carto db config.
75287 * @param {Object} config a key-value lookup. Values will replace current values
75288 * in the config.
75289 * @api
75290 */
75291ol.source.CartoDB.prototype.updateConfig = function(config) {
75292 ol.obj.assign(this.config_, config);
75293 this.initializeMap_();
75294};
75295
75296
75297/**
75298 * Sets the CartoDB config
75299 * @param {Object} config In the case of anonymous maps, a CartoDB configuration
75300 * object.
75301 * If using named maps, a key-value lookup with the template parameters.
75302 * @api
75303 */
75304ol.source.CartoDB.prototype.setConfig = function(config) {
75305 this.config_ = config || {};
75306 this.initializeMap_();
75307};
75308
75309
75310/**
75311 * Issue a request to initialize the CartoDB map.
75312 * @private
75313 */
75314ol.source.CartoDB.prototype.initializeMap_ = function() {
75315 var paramHash = JSON.stringify(this.config_);
75316 if (this.templateCache_[paramHash]) {
75317 this.applyTemplate_(this.templateCache_[paramHash]);
75318 return;
75319 }
75320 var mapUrl = 'https://' + this.account_ + '.cartodb.com/api/v1/map';
75321
75322 if (this.mapId_) {
75323 mapUrl += '/named/' + this.mapId_;
75324 }
75325
75326 var client = new XMLHttpRequest();
75327 client.addEventListener('load', this.handleInitResponse_.bind(this, paramHash));
75328 client.addEventListener('error', this.handleInitError_.bind(this));
75329 client.open('POST', mapUrl);
75330 client.setRequestHeader('Content-type', 'application/json');
75331 client.send(JSON.stringify(this.config_));
75332};
75333
75334
75335/**
75336 * Handle map initialization response.
75337 * @param {string} paramHash a hash representing the parameter set that was used
75338 * for the request
75339 * @param {Event} event Event.
75340 * @private
75341 */
75342ol.source.CartoDB.prototype.handleInitResponse_ = function(paramHash, event) {
75343 var client = /** @type {XMLHttpRequest} */ (event.target);
75344 // status will be 0 for file:// urls
75345 if (!client.status || client.status >= 200 && client.status < 300) {
75346 var response;
75347 try {
75348 response = /** @type {CartoDBLayerInfo} */(JSON.parse(client.responseText));
75349 } catch (err) {
75350 this.setState(ol.source.State.ERROR);
75351 return;
75352 }
75353 this.applyTemplate_(response);
75354 this.templateCache_[paramHash] = response;
75355 this.setState(ol.source.State.READY);
75356 } else {
75357 this.setState(ol.source.State.ERROR);
75358 }
75359};
75360
75361
75362/**
75363 * @private
75364 * @param {Event} event Event.
75365 */
75366ol.source.CartoDB.prototype.handleInitError_ = function(event) {
75367 this.setState(ol.source.State.ERROR);
75368};
75369
75370
75371/**
75372 * Apply the new tile urls returned by carto db
75373 * @param {CartoDBLayerInfo} data Result of carto db call.
75374 * @private
75375 */
75376ol.source.CartoDB.prototype.applyTemplate_ = function(data) {
75377 var tilesUrl = 'https://' + data.cdn_url.https + '/' + this.account_ +
75378 '/api/v1/map/' + data.layergroupid + '/{z}/{x}/{y}.png';
75379 this.setUrl(tilesUrl);
75380};
75381
75382// FIXME keep cluster cache by resolution ?
75383// FIXME distance not respected because of the centroid
75384
75385goog.provide('ol.source.Cluster');
75386
75387goog.require('ol');
75388goog.require('ol.asserts');
75389goog.require('ol.Feature');
75390goog.require('ol.coordinate');
75391goog.require('ol.events.EventType');
75392goog.require('ol.extent');
75393goog.require('ol.geom.Point');
75394goog.require('ol.source.Vector');
75395
75396
75397/**
75398 * @classdesc
75399 * Layer source to cluster vector data. Works out of the box with point
75400 * geometries. For other geometry types, or if not all geometries should be
75401 * considered for clustering, a custom `geometryFunction` can be defined.
75402 *
75403 * @constructor
75404 * @param {olx.source.ClusterOptions} options Constructor options.
75405 * @extends {ol.source.Vector}
75406 * @api
75407 */
75408ol.source.Cluster = function(options) {
75409 ol.source.Vector.call(this, {
75410 attributions: options.attributions,
75411 extent: options.extent,
75412 logo: options.logo,
75413 projection: options.projection,
75414 wrapX: options.wrapX
75415 });
75416
75417 /**
75418 * @type {number|undefined}
75419 * @protected
75420 */
75421 this.resolution = undefined;
75422
75423 /**
75424 * @type {number}
75425 * @protected
75426 */
75427 this.distance = options.distance !== undefined ? options.distance : 20;
75428
75429 /**
75430 * @type {Array.<ol.Feature>}
75431 * @protected
75432 */
75433 this.features = [];
75434
75435 /**
75436 * @param {ol.Feature} feature Feature.
75437 * @return {ol.geom.Point} Cluster calculation point.
75438 * @protected
75439 */
75440 this.geometryFunction = options.geometryFunction || function(feature) {
75441 var geometry = /** @type {ol.geom.Point} */ (feature.getGeometry());
75442 ol.asserts.assert(geometry instanceof ol.geom.Point,
75443 10); // The default `geometryFunction` can only handle `ol.geom.Point` geometries
75444 return geometry;
75445 };
75446
75447 /**
75448 * @type {ol.source.Vector}
75449 * @protected
75450 */
75451 this.source = options.source;
75452
75453 this.source.on(ol.events.EventType.CHANGE,
75454 ol.source.Cluster.prototype.refresh, this);
75455};
75456ol.inherits(ol.source.Cluster, ol.source.Vector);
75457
75458
75459/**
75460 * Get the distance in pixels between clusters.
75461 * @return {number} Distance.
75462 * @api
75463 */
75464ol.source.Cluster.prototype.getDistance = function() {
75465 return this.distance;
75466};
75467
75468
75469/**
75470 * Get a reference to the wrapped source.
75471 * @return {ol.source.Vector} Source.
75472 * @api
75473 */
75474ol.source.Cluster.prototype.getSource = function() {
75475 return this.source;
75476};
75477
75478
75479/**
75480 * @inheritDoc
75481 */
75482ol.source.Cluster.prototype.loadFeatures = function(extent, resolution,
75483 projection) {
75484 this.source.loadFeatures(extent, resolution, projection);
75485 if (resolution !== this.resolution) {
75486 this.clear();
75487 this.resolution = resolution;
75488 this.cluster();
75489 this.addFeatures(this.features);
75490 }
75491};
75492
75493
75494/**
75495 * Set the distance in pixels between clusters.
75496 * @param {number} distance The distance in pixels.
75497 * @api
75498 */
75499ol.source.Cluster.prototype.setDistance = function(distance) {
75500 this.distance = distance;
75501 this.refresh();
75502};
75503
75504
75505/**
75506 * handle the source changing
75507 * @override
75508 */
75509ol.source.Cluster.prototype.refresh = function() {
75510 this.clear();
75511 this.cluster();
75512 this.addFeatures(this.features);
75513 ol.source.Vector.prototype.refresh.call(this);
75514};
75515
75516
75517/**
75518 * @protected
75519 */
75520ol.source.Cluster.prototype.cluster = function() {
75521 if (this.resolution === undefined) {
75522 return;
75523 }
75524 this.features.length = 0;
75525 var extent = ol.extent.createEmpty();
75526 var mapDistance = this.distance * this.resolution;
75527 var features = this.source.getFeatures();
75528
75529 /**
75530 * @type {!Object.<string, boolean>}
75531 */
75532 var clustered = {};
75533
75534 for (var i = 0, ii = features.length; i < ii; i++) {
75535 var feature = features[i];
75536 if (!(ol.getUid(feature).toString() in clustered)) {
75537 var geometry = this.geometryFunction(feature);
75538 if (geometry) {
75539 var coordinates = geometry.getCoordinates();
75540 ol.extent.createOrUpdateFromCoordinate(coordinates, extent);
75541 ol.extent.buffer(extent, mapDistance, extent);
75542
75543 var neighbors = this.source.getFeaturesInExtent(extent);
75544 neighbors = neighbors.filter(function(neighbor) {
75545 var uid = ol.getUid(neighbor).toString();
75546 if (!(uid in clustered)) {
75547 clustered[uid] = true;
75548 return true;
75549 } else {
75550 return false;
75551 }
75552 });
75553 this.features.push(this.createCluster(neighbors));
75554 }
75555 }
75556 }
75557};
75558
75559
75560/**
75561 * @param {Array.<ol.Feature>} features Features
75562 * @return {ol.Feature} The cluster feature.
75563 * @protected
75564 */
75565ol.source.Cluster.prototype.createCluster = function(features) {
75566 var centroid = [0, 0];
75567 for (var i = features.length - 1; i >= 0; --i) {
75568 var geometry = this.geometryFunction(features[i]);
75569 if (geometry) {
75570 ol.coordinate.add(centroid, geometry.getCoordinates());
75571 } else {
75572 features.splice(i, 1);
75573 }
75574 }
75575 ol.coordinate.scale(centroid, 1 / features.length);
75576
75577 var cluster = new ol.Feature(new ol.geom.Point(centroid));
75578 cluster.set('features', features);
75579 return cluster;
75580};
75581
75582goog.provide('ol.uri');
75583
75584
75585/**
75586 * Appends query parameters to a URI.
75587 *
75588 * @param {string} uri The original URI, which may already have query data.
75589 * @param {!Object} params An object where keys are URI-encoded parameter keys,
75590 * and the values are arbitrary types or arrays.
75591 * @return {string} The new URI.
75592 */
75593ol.uri.appendParams = function(uri, params) {
75594 var keyParams = [];
75595 // Skip any null or undefined parameter values
75596 Object.keys(params).forEach(function(k) {
75597 if (params[k] !== null && params[k] !== undefined) {
75598 keyParams.push(k + '=' + encodeURIComponent(params[k]));
75599 }
75600 });
75601 var qs = keyParams.join('&');
75602 // remove any trailing ? or &
75603 uri = uri.replace(/[?&]$/, '');
75604 // append ? or & depending on whether uri has existing parameters
75605 uri = uri.indexOf('?') === -1 ? uri + '?' : uri + '&';
75606 return uri + qs;
75607};
75608
75609goog.provide('ol.source.ImageArcGISRest');
75610
75611goog.require('ol');
75612goog.require('ol.Image');
75613goog.require('ol.asserts');
75614goog.require('ol.events');
75615goog.require('ol.events.EventType');
75616goog.require('ol.extent');
75617goog.require('ol.obj');
75618goog.require('ol.source.Image');
75619goog.require('ol.uri');
75620
75621
75622/**
75623 * @classdesc
75624 * Source for data from ArcGIS Rest services providing single, untiled images.
75625 * Useful when underlying map service has labels.
75626 *
75627 * If underlying map service is not using labels,
75628 * take advantage of ol image caching and use
75629 * {@link ol.source.TileArcGISRest} data source.
75630 *
75631 * @constructor
75632 * @fires ol.source.Image.Event
75633 * @extends {ol.source.Image}
75634 * @param {olx.source.ImageArcGISRestOptions=} opt_options Image ArcGIS Rest Options.
75635 * @api
75636 */
75637ol.source.ImageArcGISRest = function(opt_options) {
75638
75639 var options = opt_options || {};
75640
75641 ol.source.Image.call(this, {
75642 attributions: options.attributions,
75643 logo: options.logo,
75644 projection: options.projection,
75645 resolutions: options.resolutions
75646 });
75647
75648 /**
75649 * @private
75650 * @type {?string}
75651 */
75652 this.crossOrigin_ =
75653 options.crossOrigin !== undefined ? options.crossOrigin : null;
75654
75655 /**
75656 * @private
75657 * @type {boolean}
75658 */
75659 this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
75660
75661 /**
75662 * @private
75663 * @type {string|undefined}
75664 */
75665 this.url_ = options.url;
75666
75667 /**
75668 * @private
75669 * @type {ol.ImageLoadFunctionType}
75670 */
75671 this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
75672 options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
75673
75674
75675 /**
75676 * @private
75677 * @type {!Object}
75678 */
75679 this.params_ = options.params || {};
75680
75681 /**
75682 * @private
75683 * @type {ol.Image}
75684 */
75685 this.image_ = null;
75686
75687 /**
75688 * @private
75689 * @type {ol.Size}
75690 */
75691 this.imageSize_ = [0, 0];
75692
75693
75694 /**
75695 * @private
75696 * @type {number}
75697 */
75698 this.renderedRevision_ = 0;
75699
75700 /**
75701 * @private
75702 * @type {number}
75703 */
75704 this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
75705
75706};
75707ol.inherits(ol.source.ImageArcGISRest, ol.source.Image);
75708
75709
75710/**
75711 * Get the user-provided params, i.e. those passed to the constructor through
75712 * the "params" option, and possibly updated using the updateParams method.
75713 * @return {Object} Params.
75714 * @api
75715 */
75716ol.source.ImageArcGISRest.prototype.getParams = function() {
75717 return this.params_;
75718};
75719
75720
75721/**
75722 * @inheritDoc
75723 */
75724ol.source.ImageArcGISRest.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
75725
75726 if (this.url_ === undefined) {
75727 return null;
75728 }
75729
75730 resolution = this.findNearestResolution(resolution);
75731 pixelRatio = this.hidpi_ ? pixelRatio : 1;
75732
75733 var image = this.image_;
75734 if (image &&
75735 this.renderedRevision_ == this.getRevision() &&
75736 image.getResolution() == resolution &&
75737 image.getPixelRatio() == pixelRatio &&
75738 ol.extent.containsExtent(image.getExtent(), extent)) {
75739 return image;
75740 }
75741
75742 var params = {
75743 'F': 'image',
75744 'FORMAT': 'PNG32',
75745 'TRANSPARENT': true
75746 };
75747 ol.obj.assign(params, this.params_);
75748
75749 extent = extent.slice();
75750 var centerX = (extent[0] + extent[2]) / 2;
75751 var centerY = (extent[1] + extent[3]) / 2;
75752 if (this.ratio_ != 1) {
75753 var halfWidth = this.ratio_ * ol.extent.getWidth(extent) / 2;
75754 var halfHeight = this.ratio_ * ol.extent.getHeight(extent) / 2;
75755 extent[0] = centerX - halfWidth;
75756 extent[1] = centerY - halfHeight;
75757 extent[2] = centerX + halfWidth;
75758 extent[3] = centerY + halfHeight;
75759 }
75760
75761 var imageResolution = resolution / pixelRatio;
75762
75763 // Compute an integer width and height.
75764 var width = Math.ceil(ol.extent.getWidth(extent) / imageResolution);
75765 var height = Math.ceil(ol.extent.getHeight(extent) / imageResolution);
75766
75767 // Modify the extent to match the integer width and height.
75768 extent[0] = centerX - imageResolution * width / 2;
75769 extent[2] = centerX + imageResolution * width / 2;
75770 extent[1] = centerY - imageResolution * height / 2;
75771 extent[3] = centerY + imageResolution * height / 2;
75772
75773 this.imageSize_[0] = width;
75774 this.imageSize_[1] = height;
75775
75776 var url = this.getRequestUrl_(extent, this.imageSize_, pixelRatio,
75777 projection, params);
75778
75779 this.image_ = new ol.Image(extent, resolution, pixelRatio,
75780 this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
75781
75782 this.renderedRevision_ = this.getRevision();
75783
75784 ol.events.listen(this.image_, ol.events.EventType.CHANGE,
75785 this.handleImageChange, this);
75786
75787 return this.image_;
75788
75789};
75790
75791
75792/**
75793 * Return the image load function of the source.
75794 * @return {ol.ImageLoadFunctionType} The image load function.
75795 * @api
75796 */
75797ol.source.ImageArcGISRest.prototype.getImageLoadFunction = function() {
75798 return this.imageLoadFunction_;
75799};
75800
75801
75802/**
75803 * @param {ol.Extent} extent Extent.
75804 * @param {ol.Size} size Size.
75805 * @param {number} pixelRatio Pixel ratio.
75806 * @param {ol.proj.Projection} projection Projection.
75807 * @param {Object} params Params.
75808 * @return {string} Request URL.
75809 * @private
75810 */
75811ol.source.ImageArcGISRest.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {
75812 // ArcGIS Server only wants the numeric portion of the projection ID.
75813 var srid = projection.getCode().split(':').pop();
75814
75815 params['SIZE'] = size[0] + ',' + size[1];
75816 params['BBOX'] = extent.join(',');
75817 params['BBOXSR'] = srid;
75818 params['IMAGESR'] = srid;
75819 params['DPI'] = Math.round(90 * pixelRatio);
75820
75821 var url = this.url_;
75822
75823 var modifiedUrl = url
75824 .replace(/MapServer\/?$/, 'MapServer/export')
75825 .replace(/ImageServer\/?$/, 'ImageServer/exportImage');
75826 if (modifiedUrl == url) {
75827 ol.asserts.assert(false, 50); // `options.featureTypes` should be an Array
75828 }
75829 return ol.uri.appendParams(modifiedUrl, params);
75830};
75831
75832
75833/**
75834 * Return the URL used for this ArcGIS source.
75835 * @return {string|undefined} URL.
75836 * @api
75837 */
75838ol.source.ImageArcGISRest.prototype.getUrl = function() {
75839 return this.url_;
75840};
75841
75842
75843/**
75844 * Set the image load function of the source.
75845 * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
75846 * @api
75847 */
75848ol.source.ImageArcGISRest.prototype.setImageLoadFunction = function(imageLoadFunction) {
75849 this.image_ = null;
75850 this.imageLoadFunction_ = imageLoadFunction;
75851 this.changed();
75852};
75853
75854
75855/**
75856 * Set the URL to use for requests.
75857 * @param {string|undefined} url URL.
75858 * @api
75859 */
75860ol.source.ImageArcGISRest.prototype.setUrl = function(url) {
75861 if (url != this.url_) {
75862 this.url_ = url;
75863 this.image_ = null;
75864 this.changed();
75865 }
75866};
75867
75868
75869/**
75870 * Update the user-provided params.
75871 * @param {Object} params Params.
75872 * @api
75873 */
75874ol.source.ImageArcGISRest.prototype.updateParams = function(params) {
75875 ol.obj.assign(this.params_, params);
75876 this.image_ = null;
75877 this.changed();
75878};
75879
75880goog.provide('ol.source.ImageMapGuide');
75881
75882goog.require('ol');
75883goog.require('ol.Image');
75884goog.require('ol.events');
75885goog.require('ol.events.EventType');
75886goog.require('ol.extent');
75887goog.require('ol.obj');
75888goog.require('ol.source.Image');
75889goog.require('ol.uri');
75890
75891
75892/**
75893 * @classdesc
75894 * Source for images from Mapguide servers
75895 *
75896 * @constructor
75897 * @fires ol.source.Image.Event
75898 * @extends {ol.source.Image}
75899 * @param {olx.source.ImageMapGuideOptions} options Options.
75900 * @api
75901 */
75902ol.source.ImageMapGuide = function(options) {
75903
75904 ol.source.Image.call(this, {
75905 projection: options.projection,
75906 resolutions: options.resolutions
75907 });
75908
75909 /**
75910 * @private
75911 * @type {?string}
75912 */
75913 this.crossOrigin_ =
75914 options.crossOrigin !== undefined ? options.crossOrigin : null;
75915
75916 /**
75917 * @private
75918 * @type {number}
75919 */
75920 this.displayDpi_ = options.displayDpi !== undefined ?
75921 options.displayDpi : 96;
75922
75923 /**
75924 * @private
75925 * @type {!Object}
75926 */
75927 this.params_ = options.params || {};
75928
75929 /**
75930 * @private
75931 * @type {string|undefined}
75932 */
75933 this.url_ = options.url;
75934
75935 /**
75936 * @private
75937 * @type {ol.ImageLoadFunctionType}
75938 */
75939 this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
75940 options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
75941
75942 /**
75943 * @private
75944 * @type {boolean}
75945 */
75946 this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
75947
75948 /**
75949 * @private
75950 * @type {number}
75951 */
75952 this.metersPerUnit_ = options.metersPerUnit !== undefined ?
75953 options.metersPerUnit : 1;
75954
75955 /**
75956 * @private
75957 * @type {number}
75958 */
75959 this.ratio_ = options.ratio !== undefined ? options.ratio : 1;
75960
75961 /**
75962 * @private
75963 * @type {boolean}
75964 */
75965 this.useOverlay_ = options.useOverlay !== undefined ?
75966 options.useOverlay : false;
75967
75968 /**
75969 * @private
75970 * @type {ol.Image}
75971 */
75972 this.image_ = null;
75973
75974 /**
75975 * @private
75976 * @type {number}
75977 */
75978 this.renderedRevision_ = 0;
75979
75980};
75981ol.inherits(ol.source.ImageMapGuide, ol.source.Image);
75982
75983
75984/**
75985 * Get the user-provided params, i.e. those passed to the constructor through
75986 * the "params" option, and possibly updated using the updateParams method.
75987 * @return {Object} Params.
75988 * @api
75989 */
75990ol.source.ImageMapGuide.prototype.getParams = function() {
75991 return this.params_;
75992};
75993
75994
75995/**
75996 * @inheritDoc
75997 */
75998ol.source.ImageMapGuide.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
75999 resolution = this.findNearestResolution(resolution);
76000 pixelRatio = this.hidpi_ ? pixelRatio : 1;
76001
76002 var image = this.image_;
76003 if (image &&
76004 this.renderedRevision_ == this.getRevision() &&
76005 image.getResolution() == resolution &&
76006 image.getPixelRatio() == pixelRatio &&
76007 ol.extent.containsExtent(image.getExtent(), extent)) {
76008 return image;
76009 }
76010
76011 if (this.ratio_ != 1) {
76012 extent = extent.slice();
76013 ol.extent.scaleFromCenter(extent, this.ratio_);
76014 }
76015 var width = ol.extent.getWidth(extent) / resolution;
76016 var height = ol.extent.getHeight(extent) / resolution;
76017 var size = [width * pixelRatio, height * pixelRatio];
76018
76019 if (this.url_ !== undefined) {
76020 var imageUrl = this.getUrl(this.url_, this.params_, extent, size,
76021 projection);
76022 image = new ol.Image(extent, resolution, pixelRatio,
76023 this.getAttributions(), imageUrl, this.crossOrigin_,
76024 this.imageLoadFunction_);
76025 ol.events.listen(image, ol.events.EventType.CHANGE,
76026 this.handleImageChange, this);
76027 } else {
76028 image = null;
76029 }
76030 this.image_ = image;
76031 this.renderedRevision_ = this.getRevision();
76032
76033 return image;
76034};
76035
76036
76037/**
76038 * Return the image load function of the source.
76039 * @return {ol.ImageLoadFunctionType} The image load function.
76040 * @api
76041 */
76042ol.source.ImageMapGuide.prototype.getImageLoadFunction = function() {
76043 return this.imageLoadFunction_;
76044};
76045
76046
76047/**
76048 * @param {ol.Extent} extent The map extents.
76049 * @param {ol.Size} size The viewport size.
76050 * @param {number} metersPerUnit The meters-per-unit value.
76051 * @param {number} dpi The display resolution.
76052 * @return {number} The computed map scale.
76053 */
76054ol.source.ImageMapGuide.getScale = function(extent, size, metersPerUnit, dpi) {
76055 var mcsW = ol.extent.getWidth(extent);
76056 var mcsH = ol.extent.getHeight(extent);
76057 var devW = size[0];
76058 var devH = size[1];
76059 var mpp = 0.0254 / dpi;
76060 if (devH * mcsW > devW * mcsH) {
76061 return mcsW * metersPerUnit / (devW * mpp); // width limited
76062 } else {
76063 return mcsH * metersPerUnit / (devH * mpp); // height limited
76064 }
76065};
76066
76067
76068/**
76069 * Update the user-provided params.
76070 * @param {Object} params Params.
76071 * @api
76072 */
76073ol.source.ImageMapGuide.prototype.updateParams = function(params) {
76074 ol.obj.assign(this.params_, params);
76075 this.changed();
76076};
76077
76078
76079/**
76080 * @param {string} baseUrl The mapagent url.
76081 * @param {Object.<string, string|number>} params Request parameters.
76082 * @param {ol.Extent} extent Extent.
76083 * @param {ol.Size} size Size.
76084 * @param {ol.proj.Projection} projection Projection.
76085 * @return {string} The mapagent map image request URL.
76086 */
76087ol.source.ImageMapGuide.prototype.getUrl = function(baseUrl, params, extent, size, projection) {
76088 var scale = ol.source.ImageMapGuide.getScale(extent, size,
76089 this.metersPerUnit_, this.displayDpi_);
76090 var center = ol.extent.getCenter(extent);
76091 var baseParams = {
76092 'OPERATION': this.useOverlay_ ? 'GETDYNAMICMAPOVERLAYIMAGE' : 'GETMAPIMAGE',
76093 'VERSION': '2.0.0',
76094 'LOCALE': 'en',
76095 'CLIENTAGENT': 'ol.source.ImageMapGuide source',
76096 'CLIP': '1',
76097 'SETDISPLAYDPI': this.displayDpi_,
76098 'SETDISPLAYWIDTH': Math.round(size[0]),
76099 'SETDISPLAYHEIGHT': Math.round(size[1]),
76100 'SETVIEWSCALE': scale,
76101 'SETVIEWCENTERX': center[0],
76102 'SETVIEWCENTERY': center[1]
76103 };
76104 ol.obj.assign(baseParams, params);
76105 return ol.uri.appendParams(baseUrl, baseParams);
76106};
76107
76108
76109/**
76110 * Set the image load function of the MapGuide source.
76111 * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
76112 * @api
76113 */
76114ol.source.ImageMapGuide.prototype.setImageLoadFunction = function(
76115 imageLoadFunction) {
76116 this.image_ = null;
76117 this.imageLoadFunction_ = imageLoadFunction;
76118 this.changed();
76119};
76120
76121goog.provide('ol.source.ImageStatic');
76122
76123goog.require('ol');
76124goog.require('ol.Image');
76125goog.require('ol.ImageState');
76126goog.require('ol.dom');
76127goog.require('ol.events');
76128goog.require('ol.events.EventType');
76129goog.require('ol.extent');
76130goog.require('ol.proj');
76131goog.require('ol.source.Image');
76132
76133
76134/**
76135 * @classdesc
76136 * A layer source for displaying a single, static image.
76137 *
76138 * @constructor
76139 * @extends {ol.source.Image}
76140 * @param {olx.source.ImageStaticOptions} options Options.
76141 * @api
76142 */
76143ol.source.ImageStatic = function(options) {
76144 var imageExtent = options.imageExtent;
76145
76146 var crossOrigin = options.crossOrigin !== undefined ?
76147 options.crossOrigin : null;
76148
76149 var /** @type {ol.ImageLoadFunctionType} */ imageLoadFunction =
76150 options.imageLoadFunction !== undefined ?
76151 options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
76152
76153 ol.source.Image.call(this, {
76154 attributions: options.attributions,
76155 logo: options.logo,
76156 projection: ol.proj.get(options.projection)
76157 });
76158
76159 /**
76160 * @private
76161 * @type {ol.Image}
76162 */
76163 this.image_ = new ol.Image(imageExtent, undefined, 1, this.getAttributions(),
76164 options.url, crossOrigin, imageLoadFunction);
76165
76166 /**
76167 * @private
76168 * @type {ol.Size}
76169 */
76170 this.imageSize_ = options.imageSize ? options.imageSize : null;
76171
76172 ol.events.listen(this.image_, ol.events.EventType.CHANGE,
76173 this.handleImageChange, this);
76174
76175};
76176ol.inherits(ol.source.ImageStatic, ol.source.Image);
76177
76178
76179/**
76180 * @inheritDoc
76181 */
76182ol.source.ImageStatic.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
76183 if (ol.extent.intersects(extent, this.image_.getExtent())) {
76184 return this.image_;
76185 }
76186 return null;
76187};
76188
76189
76190/**
76191 * @inheritDoc
76192 */
76193ol.source.ImageStatic.prototype.handleImageChange = function(evt) {
76194 if (this.image_.getState() == ol.ImageState.LOADED) {
76195 var imageExtent = this.image_.getExtent();
76196 var image = this.image_.getImage();
76197 var imageWidth, imageHeight;
76198 if (this.imageSize_) {
76199 imageWidth = this.imageSize_[0];
76200 imageHeight = this.imageSize_[1];
76201 } else {
76202 imageWidth = image.width;
76203 imageHeight = image.height;
76204 }
76205 var resolution = ol.extent.getHeight(imageExtent) / imageHeight;
76206 var targetWidth = Math.ceil(ol.extent.getWidth(imageExtent) / resolution);
76207 if (targetWidth != imageWidth) {
76208 var context = ol.dom.createCanvasContext2D(targetWidth, imageHeight);
76209 var canvas = context.canvas;
76210 context.drawImage(image, 0, 0, imageWidth, imageHeight,
76211 0, 0, canvas.width, canvas.height);
76212 this.image_.setImage(canvas);
76213 }
76214 }
76215 ol.source.Image.prototype.handleImageChange.call(this, evt);
76216};
76217
76218goog.provide('ol.source.WMSServerType');
76219
76220
76221/**
76222 * Available server types: `'carmentaserver'`, `'geoserver'`, `'mapserver'`,
76223 * `'qgis'`. These are servers that have vendor parameters beyond the WMS
76224 * specification that OpenLayers can make use of.
76225 * @enum {string}
76226 */
76227ol.source.WMSServerType = {
76228 CARMENTA_SERVER: 'carmentaserver',
76229 GEOSERVER: 'geoserver',
76230 MAPSERVER: 'mapserver',
76231 QGIS: 'qgis'
76232};
76233
76234// FIXME cannot be shared between maps with different projections
76235
76236goog.provide('ol.source.ImageWMS');
76237
76238goog.require('ol');
76239goog.require('ol.Image');
76240goog.require('ol.asserts');
76241goog.require('ol.events');
76242goog.require('ol.events.EventType');
76243goog.require('ol.extent');
76244goog.require('ol.obj');
76245goog.require('ol.proj');
76246goog.require('ol.source.Image');
76247goog.require('ol.source.WMSServerType');
76248goog.require('ol.string');
76249goog.require('ol.uri');
76250
76251
76252/**
76253 * @classdesc
76254 * Source for WMS servers providing single, untiled images.
76255 *
76256 * @constructor
76257 * @fires ol.source.Image.Event
76258 * @extends {ol.source.Image}
76259 * @param {olx.source.ImageWMSOptions=} opt_options Options.
76260 * @api
76261 */
76262ol.source.ImageWMS = function(opt_options) {
76263
76264 var options = opt_options || {};
76265
76266 ol.source.Image.call(this, {
76267 attributions: options.attributions,
76268 logo: options.logo,
76269 projection: options.projection,
76270 resolutions: options.resolutions
76271 });
76272
76273 /**
76274 * @private
76275 * @type {?string}
76276 */
76277 this.crossOrigin_ =
76278 options.crossOrigin !== undefined ? options.crossOrigin : null;
76279
76280 /**
76281 * @private
76282 * @type {string|undefined}
76283 */
76284 this.url_ = options.url;
76285
76286 /**
76287 * @private
76288 * @type {ol.ImageLoadFunctionType}
76289 */
76290 this.imageLoadFunction_ = options.imageLoadFunction !== undefined ?
76291 options.imageLoadFunction : ol.source.Image.defaultImageLoadFunction;
76292
76293 /**
76294 * @private
76295 * @type {!Object}
76296 */
76297 this.params_ = options.params || {};
76298
76299 /**
76300 * @private
76301 * @type {boolean}
76302 */
76303 this.v13_ = true;
76304 this.updateV13_();
76305
76306 /**
76307 * @private
76308 * @type {ol.source.WMSServerType|undefined}
76309 */
76310 this.serverType_ = /** @type {ol.source.WMSServerType|undefined} */ (options.serverType);
76311
76312 /**
76313 * @private
76314 * @type {boolean}
76315 */
76316 this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
76317
76318 /**
76319 * @private
76320 * @type {ol.Image}
76321 */
76322 this.image_ = null;
76323
76324 /**
76325 * @private
76326 * @type {ol.Size}
76327 */
76328 this.imageSize_ = [0, 0];
76329
76330 /**
76331 * @private
76332 * @type {number}
76333 */
76334 this.renderedRevision_ = 0;
76335
76336 /**
76337 * @private
76338 * @type {number}
76339 */
76340 this.ratio_ = options.ratio !== undefined ? options.ratio : 1.5;
76341
76342};
76343ol.inherits(ol.source.ImageWMS, ol.source.Image);
76344
76345
76346/**
76347 * @const
76348 * @type {ol.Size}
76349 * @private
76350 */
76351ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_ = [101, 101];
76352
76353
76354/**
76355 * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
76356 * projection. Return `undefined` if the GetFeatureInfo URL cannot be
76357 * constructed.
76358 * @param {ol.Coordinate} coordinate Coordinate.
76359 * @param {number} resolution Resolution.
76360 * @param {ol.ProjectionLike} projection Projection.
76361 * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
76362 * be provided. If `QUERY_LAYERS` is not provided then the layers specified
76363 * in the `LAYERS` parameter will be used. `VERSION` should not be
76364 * specified here.
76365 * @return {string|undefined} GetFeatureInfo URL.
76366 * @api
76367 */
76368ol.source.ImageWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
76369 if (this.url_ === undefined) {
76370 return undefined;
76371 }
76372
76373 var extent = ol.extent.getForViewAndSize(
76374 coordinate, resolution, 0,
76375 ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_);
76376
76377 var baseParams = {
76378 'SERVICE': 'WMS',
76379 'VERSION': ol.DEFAULT_WMS_VERSION,
76380 'REQUEST': 'GetFeatureInfo',
76381 'FORMAT': 'image/png',
76382 'TRANSPARENT': true,
76383 'QUERY_LAYERS': this.params_['LAYERS']
76384 };
76385 ol.obj.assign(baseParams, this.params_, params);
76386
76387 var x = Math.floor((coordinate[0] - extent[0]) / resolution);
76388 var y = Math.floor((extent[3] - coordinate[1]) / resolution);
76389 baseParams[this.v13_ ? 'I' : 'X'] = x;
76390 baseParams[this.v13_ ? 'J' : 'Y'] = y;
76391
76392 return this.getRequestUrl_(
76393 extent, ol.source.ImageWMS.GETFEATUREINFO_IMAGE_SIZE_,
76394 1, ol.proj.get(projection), baseParams);
76395};
76396
76397
76398/**
76399 * Get the user-provided params, i.e. those passed to the constructor through
76400 * the "params" option, and possibly updated using the updateParams method.
76401 * @return {Object} Params.
76402 * @api
76403 */
76404ol.source.ImageWMS.prototype.getParams = function() {
76405 return this.params_;
76406};
76407
76408
76409/**
76410 * @inheritDoc
76411 */
76412ol.source.ImageWMS.prototype.getImageInternal = function(extent, resolution, pixelRatio, projection) {
76413
76414 if (this.url_ === undefined) {
76415 return null;
76416 }
76417
76418 resolution = this.findNearestResolution(resolution);
76419
76420 if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
76421 pixelRatio = 1;
76422 }
76423
76424 var imageResolution = resolution / pixelRatio;
76425
76426 var center = ol.extent.getCenter(extent);
76427 var viewWidth = Math.ceil(ol.extent.getWidth(extent) / imageResolution);
76428 var viewHeight = Math.ceil(ol.extent.getHeight(extent) / imageResolution);
76429 var viewExtent = ol.extent.getForViewAndSize(center, imageResolution, 0,
76430 [viewWidth, viewHeight]);
76431 var requestWidth = Math.ceil(this.ratio_ * ol.extent.getWidth(extent) / imageResolution);
76432 var requestHeight = Math.ceil(this.ratio_ * ol.extent.getHeight(extent) / imageResolution);
76433 var requestExtent = ol.extent.getForViewAndSize(center, imageResolution, 0,
76434 [requestWidth, requestHeight]);
76435
76436 var image = this.image_;
76437 if (image &&
76438 this.renderedRevision_ == this.getRevision() &&
76439 image.getResolution() == resolution &&
76440 image.getPixelRatio() == pixelRatio &&
76441 ol.extent.containsExtent(image.getExtent(), viewExtent)) {
76442 return image;
76443 }
76444
76445 var params = {
76446 'SERVICE': 'WMS',
76447 'VERSION': ol.DEFAULT_WMS_VERSION,
76448 'REQUEST': 'GetMap',
76449 'FORMAT': 'image/png',
76450 'TRANSPARENT': true
76451 };
76452 ol.obj.assign(params, this.params_);
76453
76454 this.imageSize_[0] = Math.round(ol.extent.getWidth(requestExtent) / imageResolution);
76455 this.imageSize_[1] = Math.round(ol.extent.getHeight(requestExtent) / imageResolution);
76456
76457 var url = this.getRequestUrl_(requestExtent, this.imageSize_, pixelRatio,
76458 projection, params);
76459
76460 this.image_ = new ol.Image(requestExtent, resolution, pixelRatio,
76461 this.getAttributions(), url, this.crossOrigin_, this.imageLoadFunction_);
76462
76463 this.renderedRevision_ = this.getRevision();
76464
76465 ol.events.listen(this.image_, ol.events.EventType.CHANGE,
76466 this.handleImageChange, this);
76467
76468 return this.image_;
76469
76470};
76471
76472
76473/**
76474 * Return the image load function of the source.
76475 * @return {ol.ImageLoadFunctionType} The image load function.
76476 * @api
76477 */
76478ol.source.ImageWMS.prototype.getImageLoadFunction = function() {
76479 return this.imageLoadFunction_;
76480};
76481
76482
76483/**
76484 * @param {ol.Extent} extent Extent.
76485 * @param {ol.Size} size Size.
76486 * @param {number} pixelRatio Pixel ratio.
76487 * @param {ol.proj.Projection} projection Projection.
76488 * @param {Object} params Params.
76489 * @return {string} Request URL.
76490 * @private
76491 */
76492ol.source.ImageWMS.prototype.getRequestUrl_ = function(extent, size, pixelRatio, projection, params) {
76493
76494 ol.asserts.assert(this.url_ !== undefined, 9); // `url` must be configured or set using `#setUrl()`
76495
76496 params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
76497
76498 if (!('STYLES' in this.params_)) {
76499 params['STYLES'] = '';
76500 }
76501
76502 if (pixelRatio != 1) {
76503 switch (this.serverType_) {
76504 case ol.source.WMSServerType.GEOSERVER:
76505 var dpi = (90 * pixelRatio + 0.5) | 0;
76506 if ('FORMAT_OPTIONS' in params) {
76507 params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
76508 } else {
76509 params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
76510 }
76511 break;
76512 case ol.source.WMSServerType.MAPSERVER:
76513 params['MAP_RESOLUTION'] = 90 * pixelRatio;
76514 break;
76515 case ol.source.WMSServerType.CARMENTA_SERVER:
76516 case ol.source.WMSServerType.QGIS:
76517 params['DPI'] = 90 * pixelRatio;
76518 break;
76519 default:
76520 ol.asserts.assert(false, 8); // Unknown `serverType` configured
76521 break;
76522 }
76523 }
76524
76525 params['WIDTH'] = size[0];
76526 params['HEIGHT'] = size[1];
76527
76528 var axisOrientation = projection.getAxisOrientation();
76529 var bbox;
76530 if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
76531 bbox = [extent[1], extent[0], extent[3], extent[2]];
76532 } else {
76533 bbox = extent;
76534 }
76535 params['BBOX'] = bbox.join(',');
76536
76537 return ol.uri.appendParams(/** @type {string} */ (this.url_), params);
76538};
76539
76540
76541/**
76542 * Return the URL used for this WMS source.
76543 * @return {string|undefined} URL.
76544 * @api
76545 */
76546ol.source.ImageWMS.prototype.getUrl = function() {
76547 return this.url_;
76548};
76549
76550
76551/**
76552 * Set the image load function of the source.
76553 * @param {ol.ImageLoadFunctionType} imageLoadFunction Image load function.
76554 * @api
76555 */
76556ol.source.ImageWMS.prototype.setImageLoadFunction = function(
76557 imageLoadFunction) {
76558 this.image_ = null;
76559 this.imageLoadFunction_ = imageLoadFunction;
76560 this.changed();
76561};
76562
76563
76564/**
76565 * Set the URL to use for requests.
76566 * @param {string|undefined} url URL.
76567 * @api
76568 */
76569ol.source.ImageWMS.prototype.setUrl = function(url) {
76570 if (url != this.url_) {
76571 this.url_ = url;
76572 this.image_ = null;
76573 this.changed();
76574 }
76575};
76576
76577
76578/**
76579 * Update the user-provided params.
76580 * @param {Object} params Params.
76581 * @api
76582 */
76583ol.source.ImageWMS.prototype.updateParams = function(params) {
76584 ol.obj.assign(this.params_, params);
76585 this.updateV13_();
76586 this.image_ = null;
76587 this.changed();
76588};
76589
76590
76591/**
76592 * @private
76593 */
76594ol.source.ImageWMS.prototype.updateV13_ = function() {
76595 var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;
76596 this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;
76597};
76598
76599goog.provide('ol.source.OSM');
76600
76601goog.require('ol');
76602goog.require('ol.Attribution');
76603goog.require('ol.source.XYZ');
76604
76605
76606/**
76607 * @classdesc
76608 * Layer source for the OpenStreetMap tile server.
76609 *
76610 * @constructor
76611 * @extends {ol.source.XYZ}
76612 * @param {olx.source.OSMOptions=} opt_options Open Street Map options.
76613 * @api
76614 */
76615ol.source.OSM = function(opt_options) {
76616
76617 var options = opt_options || {};
76618
76619 var attributions;
76620 if (options.attributions !== undefined) {
76621 attributions = options.attributions;
76622 } else {
76623 attributions = [ol.source.OSM.ATTRIBUTION];
76624 }
76625
76626 var crossOrigin = options.crossOrigin !== undefined ?
76627 options.crossOrigin : 'anonymous';
76628
76629 var url = options.url !== undefined ?
76630 options.url : 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png';
76631
76632 ol.source.XYZ.call(this, {
76633 attributions: attributions,
76634 cacheSize: options.cacheSize,
76635 crossOrigin: crossOrigin,
76636 opaque: options.opaque !== undefined ? options.opaque : true,
76637 maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,
76638 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
76639 tileLoadFunction: options.tileLoadFunction,
76640 url: url,
76641 wrapX: options.wrapX
76642 });
76643
76644};
76645ol.inherits(ol.source.OSM, ol.source.XYZ);
76646
76647
76648/**
76649 * The attribution containing a link to the OpenStreetMap Copyright and License
76650 * page.
76651 * @const
76652 * @type {ol.Attribution}
76653 * @api
76654 */
76655ol.source.OSM.ATTRIBUTION = new ol.Attribution({
76656 html: '&copy; ' +
76657 '<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> ' +
76658 'contributors.'
76659});
76660
76661
76662/**
76663 * @fileoverview
76664 * @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, unusedLocalVariables, uselessCode, visibility}
76665 */
76666goog.provide('ol.ext.pixelworks.Processor');
76667
76668/** @typedef {function(*)} */
76669ol.ext.pixelworks.Processor = function() {};
76670
76671(function() {(function (exports) {
76672'use strict';
76673
76674var hasImageData = true;
76675try {
76676 new ImageData(10, 10);
76677} catch (_) {
76678 hasImageData = false;
76679}
76680var context = document.createElement('canvas').getContext('2d');
76681function newImageData$1(data, width, height) {
76682 if (hasImageData) {
76683 return new ImageData(data, width, height);
76684 } else {
76685 var imageData = context.createImageData(width, height);
76686 imageData.data.set(data);
76687 return imageData;
76688 }
76689}
76690var newImageData_1 = newImageData$1;
76691var util = {
76692 newImageData: newImageData_1
76693};
76694
76695var newImageData = util.newImageData;
76696function createMinion(operation) {
76697 var workerHasImageData = true;
76698 try {
76699 new ImageData(10, 10);
76700 } catch (_) {
76701 workerHasImageData = false;
76702 }
76703 function newWorkerImageData(data, width, height) {
76704 if (workerHasImageData) {
76705 return new ImageData(data, width, height);
76706 } else {
76707 return {data: data, width: width, height: height};
76708 }
76709 }
76710 return function(data) {
76711 var buffers = data['buffers'];
76712 var meta = data['meta'];
76713 var imageOps = data['imageOps'];
76714 var width = data['width'];
76715 var height = data['height'];
76716 var numBuffers = buffers.length;
76717 var numBytes = buffers[0].byteLength;
76718 var output, b;
76719 if (imageOps) {
76720 var images = new Array(numBuffers);
76721 for (b = 0; b < numBuffers; ++b) {
76722 images[b] = newWorkerImageData(
76723 new Uint8ClampedArray(buffers[b]), width, height);
76724 }
76725 output = operation(images, meta).data;
76726 } else {
76727 output = new Uint8ClampedArray(numBytes);
76728 var arrays = new Array(numBuffers);
76729 var pixels = new Array(numBuffers);
76730 for (b = 0; b < numBuffers; ++b) {
76731 arrays[b] = new Uint8ClampedArray(buffers[b]);
76732 pixels[b] = [0, 0, 0, 0];
76733 }
76734 for (var i = 0; i < numBytes; i += 4) {
76735 for (var j = 0; j < numBuffers; ++j) {
76736 var array = arrays[j];
76737 pixels[j][0] = array[i];
76738 pixels[j][1] = array[i + 1];
76739 pixels[j][2] = array[i + 2];
76740 pixels[j][3] = array[i + 3];
76741 }
76742 var pixel = operation(pixels, meta);
76743 output[i] = pixel[0];
76744 output[i + 1] = pixel[1];
76745 output[i + 2] = pixel[2];
76746 output[i + 3] = pixel[3];
76747 }
76748 }
76749 return output.buffer;
76750 };
76751}
76752function createWorker(config, onMessage) {
76753 var lib = Object.keys(config.lib || {}).map(function(name) {
76754 return 'var ' + name + ' = ' + config.lib[name].toString() + ';';
76755 });
76756 var lines = lib.concat([
76757 'var __minion__ = (' + createMinion.toString() + ')(', config.operation.toString(), ');',
76758 'self.addEventListener("message", function(event) {',
76759 ' var buffer = __minion__(event.data);',
76760 ' self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);',
76761 '});'
76762 ]);
76763 var blob = new Blob(lines, {type: 'text/javascript'});
76764 var source = URL.createObjectURL(blob);
76765 var worker = new Worker(source);
76766 worker.addEventListener('message', onMessage);
76767 return worker;
76768}
76769function createFauxWorker(config, onMessage) {
76770 var minion = createMinion(config.operation);
76771 return {
76772 postMessage: function(data) {
76773 setTimeout(function() {
76774 onMessage({'data': {'buffer': minion(data), 'meta': data['meta']}});
76775 }, 0);
76776 }
76777 };
76778}
76779function Processor(config) {
76780 this._imageOps = !!config.imageOps;
76781 var threads;
76782 if (config.threads === 0) {
76783 threads = 0;
76784 } else if (this._imageOps) {
76785 threads = 1;
76786 } else {
76787 threads = config.threads || 1;
76788 }
76789 var workers = [];
76790 if (threads) {
76791 for (var i = 0; i < threads; ++i) {
76792 workers[i] = createWorker(config, this._onWorkerMessage.bind(this, i));
76793 }
76794 } else {
76795 workers[0] = createFauxWorker(config, this._onWorkerMessage.bind(this, 0));
76796 }
76797 this._workers = workers;
76798 this._queue = [];
76799 this._maxQueueLength = config.queue || Infinity;
76800 this._running = 0;
76801 this._dataLookup = {};
76802 this._job = null;
76803}
76804Processor.prototype.process = function(inputs, meta, callback) {
76805 this._enqueue({
76806 inputs: inputs,
76807 meta: meta,
76808 callback: callback
76809 });
76810 this._dispatch();
76811};
76812Processor.prototype.destroy = function() {
76813 for (var key in this) {
76814 this[key] = null;
76815 }
76816 this._destroyed = true;
76817};
76818Processor.prototype._enqueue = function(job) {
76819 this._queue.push(job);
76820 while (this._queue.length > this._maxQueueLength) {
76821 this._queue.shift().callback(null, null);
76822 }
76823};
76824Processor.prototype._dispatch = function() {
76825 if (this._running === 0 && this._queue.length > 0) {
76826 var job = this._job = this._queue.shift();
76827 var width = job.inputs[0].width;
76828 var height = job.inputs[0].height;
76829 var buffers = job.inputs.map(function(input) {
76830 return input.data.buffer;
76831 });
76832 var threads = this._workers.length;
76833 this._running = threads;
76834 if (threads === 1) {
76835 this._workers[0].postMessage({
76836 'buffers': buffers,
76837 'meta': job.meta,
76838 'imageOps': this._imageOps,
76839 'width': width,
76840 'height': height
76841 }, buffers);
76842 } else {
76843 var length = job.inputs[0].data.length;
76844 var segmentLength = 4 * Math.ceil(length / 4 / threads);
76845 for (var i = 0; i < threads; ++i) {
76846 var offset = i * segmentLength;
76847 var slices = [];
76848 for (var j = 0, jj = buffers.length; j < jj; ++j) {
76849 slices.push(buffers[i].slice(offset, offset + segmentLength));
76850 }
76851 this._workers[i].postMessage({
76852 'buffers': slices,
76853 'meta': job.meta,
76854 'imageOps': this._imageOps,
76855 'width': width,
76856 'height': height
76857 }, slices);
76858 }
76859 }
76860 }
76861};
76862Processor.prototype._onWorkerMessage = function(index, event) {
76863 if (this._destroyed) {
76864 return;
76865 }
76866 this._dataLookup[index] = event.data;
76867 --this._running;
76868 if (this._running === 0) {
76869 this._resolveJob();
76870 }
76871};
76872Processor.prototype._resolveJob = function() {
76873 var job = this._job;
76874 var threads = this._workers.length;
76875 var data, meta;
76876 if (threads === 1) {
76877 data = new Uint8ClampedArray(this._dataLookup[0]['buffer']);
76878 meta = this._dataLookup[0]['meta'];
76879 } else {
76880 var length = job.inputs[0].data.length;
76881 data = new Uint8ClampedArray(length);
76882 meta = new Array(length);
76883 var segmentLength = 4 * Math.ceil(length / 4 / threads);
76884 for (var i = 0; i < threads; ++i) {
76885 var buffer = this._dataLookup[i]['buffer'];
76886 var offset = i * segmentLength;
76887 data.set(new Uint8ClampedArray(buffer), offset);
76888 meta[i] = this._dataLookup[i]['meta'];
76889 }
76890 }
76891 this._job = null;
76892 this._dataLookup = {};
76893 job.callback(null,
76894 newImageData(data, job.inputs[0].width, job.inputs[0].height), meta);
76895 this._dispatch();
76896};
76897var processor = Processor;
76898
76899var Processor_1 = processor;
76900var index = {
76901 Processor: Processor_1
76902};
76903
76904exports['default'] = index;
76905exports.Processor = Processor_1;
76906
76907}((this.pixelworks = this.pixelworks || {})));}).call(ol.ext);
76908
76909goog.provide('ol.source.RasterOperationType');
76910
76911/**
76912 * Raster operation type. Supported values are `'pixel'` and `'image'`.
76913 * @enum {string}
76914 */
76915ol.source.RasterOperationType = {
76916 PIXEL: 'pixel',
76917 IMAGE: 'image'
76918};
76919
76920goog.provide('ol.source.Raster');
76921
76922goog.require('ol');
76923goog.require('ol.ImageCanvas');
76924goog.require('ol.TileQueue');
76925goog.require('ol.dom');
76926goog.require('ol.events');
76927goog.require('ol.events.Event');
76928goog.require('ol.events.EventType');
76929goog.require('ol.ext.pixelworks.Processor');
76930goog.require('ol.extent');
76931goog.require('ol.layer.Image');
76932goog.require('ol.layer.Tile');
76933goog.require('ol.obj');
76934goog.require('ol.renderer.canvas.ImageLayer');
76935goog.require('ol.renderer.canvas.TileLayer');
76936goog.require('ol.source.Image');
76937goog.require('ol.source.RasterOperationType');
76938goog.require('ol.source.State');
76939goog.require('ol.source.Tile');
76940goog.require('ol.transform');
76941
76942
76943/**
76944 * @classdesc
76945 * A source that transforms data from any number of input sources using an array
76946 * of {@link ol.RasterOperation} functions to transform input pixel values into
76947 * output pixel values.
76948 *
76949 * @constructor
76950 * @extends {ol.source.Image}
76951 * @fires ol.source.Raster.Event
76952 * @param {olx.source.RasterOptions} options Options.
76953 * @api
76954 */
76955ol.source.Raster = function(options) {
76956
76957 /**
76958 * @private
76959 * @type {*}
76960 */
76961 this.worker_ = null;
76962
76963 /**
76964 * @private
76965 * @type {ol.source.RasterOperationType}
76966 */
76967 this.operationType_ = options.operationType !== undefined ?
76968 options.operationType : ol.source.RasterOperationType.PIXEL;
76969
76970 /**
76971 * @private
76972 * @type {number}
76973 */
76974 this.threads_ = options.threads !== undefined ? options.threads : 1;
76975
76976 /**
76977 * @private
76978 * @type {Array.<ol.renderer.canvas.Layer>}
76979 */
76980 this.renderers_ = ol.source.Raster.createRenderers_(options.sources);
76981
76982 for (var r = 0, rr = this.renderers_.length; r < rr; ++r) {
76983 ol.events.listen(this.renderers_[r], ol.events.EventType.CHANGE,
76984 this.changed, this);
76985 }
76986
76987 /**
76988 * @private
76989 * @type {ol.TileQueue}
76990 */
76991 this.tileQueue_ = new ol.TileQueue(
76992 function() {
76993 return 1;
76994 },
76995 this.changed.bind(this));
76996
76997 var layerStatesArray = ol.source.Raster.getLayerStatesArray_(this.renderers_);
76998 var layerStates = {};
76999 for (var i = 0, ii = layerStatesArray.length; i < ii; ++i) {
77000 layerStates[ol.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
77001 }
77002
77003 /**
77004 * The most recently requested frame state.
77005 * @type {olx.FrameState}
77006 * @private
77007 */
77008 this.requestedFrameState_;
77009
77010 /**
77011 * The most recently rendered image canvas.
77012 * @type {ol.ImageCanvas}
77013 * @private
77014 */
77015 this.renderedImageCanvas_ = null;
77016
77017 /**
77018 * The most recently rendered revision.
77019 * @type {number}
77020 */
77021 this.renderedRevision_;
77022
77023 /**
77024 * @private
77025 * @type {olx.FrameState}
77026 */
77027 this.frameState_ = {
77028 animate: false,
77029 attributions: {},
77030 coordinateToPixelTransform: ol.transform.create(),
77031 extent: null,
77032 focus: null,
77033 index: 0,
77034 layerStates: layerStates,
77035 layerStatesArray: layerStatesArray,
77036 logos: {},
77037 pixelRatio: 1,
77038 pixelToCoordinateTransform: ol.transform.create(),
77039 postRenderFunctions: [],
77040 size: [0, 0],
77041 skippedFeatureUids: {},
77042 tileQueue: this.tileQueue_,
77043 time: Date.now(),
77044 usedTiles: {},
77045 viewState: /** @type {olx.ViewState} */ ({
77046 rotation: 0
77047 }),
77048 viewHints: [],
77049 wantedTiles: {}
77050 };
77051
77052 ol.source.Image.call(this, {});
77053
77054 if (options.operation !== undefined) {
77055 this.setOperation(options.operation, options.lib);
77056 }
77057
77058};
77059ol.inherits(ol.source.Raster, ol.source.Image);
77060
77061
77062/**
77063 * Set the operation.
77064 * @param {ol.RasterOperation} operation New operation.
77065 * @param {Object=} opt_lib Functions that will be available to operations run
77066 * in a worker.
77067 * @api
77068 */
77069ol.source.Raster.prototype.setOperation = function(operation, opt_lib) {
77070 this.worker_ = new ol.ext.pixelworks.Processor({
77071 operation: operation,
77072 imageOps: this.operationType_ === ol.source.RasterOperationType.IMAGE,
77073 queue: 1,
77074 lib: opt_lib,
77075 threads: this.threads_
77076 });
77077 this.changed();
77078};
77079
77080
77081/**
77082 * Update the stored frame state.
77083 * @param {ol.Extent} extent The view extent (in map units).
77084 * @param {number} resolution The view resolution.
77085 * @param {ol.proj.Projection} projection The view projection.
77086 * @return {olx.FrameState} The updated frame state.
77087 * @private
77088 */
77089ol.source.Raster.prototype.updateFrameState_ = function(extent, resolution, projection) {
77090
77091 var frameState = /** @type {olx.FrameState} */ (
77092 ol.obj.assign({}, this.frameState_));
77093
77094 frameState.viewState = /** @type {olx.ViewState} */ (
77095 ol.obj.assign({}, frameState.viewState));
77096
77097 var center = ol.extent.getCenter(extent);
77098
77099 frameState.extent = extent.slice();
77100 frameState.focus = center;
77101 frameState.size[0] = Math.round(ol.extent.getWidth(extent) / resolution);
77102 frameState.size[1] = Math.round(ol.extent.getHeight(extent) / resolution);
77103
77104 var viewState = frameState.viewState;
77105 viewState.center = center;
77106 viewState.projection = projection;
77107 viewState.resolution = resolution;
77108 return frameState;
77109};
77110
77111
77112/**
77113 * Determine if all sources are ready.
77114 * @return {boolean} All sources are ready.
77115 * @private
77116 */
77117ol.source.Raster.prototype.allSourcesReady_ = function() {
77118 var ready = true;
77119 var source;
77120 for (var i = 0, ii = this.renderers_.length; i < ii; ++i) {
77121 source = this.renderers_[i].getLayer().getSource();
77122 if (source.getState() !== ol.source.State.READY) {
77123 ready = false;
77124 break;
77125 }
77126 }
77127 return ready;
77128};
77129
77130
77131/**
77132 * @inheritDoc
77133 */
77134ol.source.Raster.prototype.getImage = function(extent, resolution, pixelRatio, projection) {
77135 if (!this.allSourcesReady_()) {
77136 return null;
77137 }
77138
77139 var frameState = this.updateFrameState_(extent, resolution, projection);
77140 this.requestedFrameState_ = frameState;
77141
77142 // check if we can't reuse the existing ol.ImageCanvas
77143 if (this.renderedImageCanvas_) {
77144 var renderedResolution = this.renderedImageCanvas_.getResolution();
77145 var renderedExtent = this.renderedImageCanvas_.getExtent();
77146 if (resolution !== renderedResolution || !ol.extent.equals(extent, renderedExtent)) {
77147 this.renderedImageCanvas_ = null;
77148 }
77149 }
77150
77151 if (!this.renderedImageCanvas_ || this.getRevision() !== this.renderedRevision_) {
77152 this.processSources_();
77153 }
77154
77155 frameState.tileQueue.loadMoreTiles(16, 16);
77156 return this.renderedImageCanvas_;
77157};
77158
77159
77160/**
77161 * Start processing source data.
77162 * @private
77163 */
77164ol.source.Raster.prototype.processSources_ = function() {
77165 var frameState = this.requestedFrameState_;
77166 var len = this.renderers_.length;
77167 var imageDatas = new Array(len);
77168 for (var i = 0; i < len; ++i) {
77169 var imageData = ol.source.Raster.getImageData_(
77170 this.renderers_[i], frameState, frameState.layerStatesArray[i]);
77171 if (imageData) {
77172 imageDatas[i] = imageData;
77173 } else {
77174 return;
77175 }
77176 }
77177
77178 var data = {};
77179 this.dispatchEvent(new ol.source.Raster.Event(
77180 ol.source.Raster.EventType_.BEFOREOPERATIONS, frameState, data));
77181 this.worker_.process(imageDatas, data,
77182 this.onWorkerComplete_.bind(this, frameState));
77183};
77184
77185
77186/**
77187 * Called when pixel processing is complete.
77188 * @param {olx.FrameState} frameState The frame state.
77189 * @param {Error} err Any error during processing.
77190 * @param {ImageData} output The output image data.
77191 * @param {Object} data The user data.
77192 * @private
77193 */
77194ol.source.Raster.prototype.onWorkerComplete_ = function(frameState, err, output, data) {
77195 if (err || !output) {
77196 return;
77197 }
77198
77199 // do nothing if extent or resolution changed
77200 var extent = frameState.extent;
77201 var resolution = frameState.viewState.resolution;
77202 if (resolution !== this.requestedFrameState_.viewState.resolution ||
77203 !ol.extent.equals(extent, this.requestedFrameState_.extent)) {
77204 return;
77205 }
77206
77207 var context;
77208 if (this.renderedImageCanvas_) {
77209 context = this.renderedImageCanvas_.getImage().getContext('2d');
77210 } else {
77211 var width = Math.round(ol.extent.getWidth(extent) / resolution);
77212 var height = Math.round(ol.extent.getHeight(extent) / resolution);
77213 context = ol.dom.createCanvasContext2D(width, height);
77214 this.renderedImageCanvas_ = new ol.ImageCanvas(
77215 extent, resolution, 1, this.getAttributions(), context.canvas);
77216 }
77217 context.putImageData(output, 0, 0);
77218
77219 this.changed();
77220 this.renderedRevision_ = this.getRevision();
77221
77222 this.dispatchEvent(new ol.source.Raster.Event(
77223 ol.source.Raster.EventType_.AFTEROPERATIONS, frameState, data));
77224};
77225
77226
77227/**
77228 * Get image data from a renderer.
77229 * @param {ol.renderer.canvas.Layer} renderer Layer renderer.
77230 * @param {olx.FrameState} frameState The frame state.
77231 * @param {ol.LayerState} layerState The layer state.
77232 * @return {ImageData} The image data.
77233 * @private
77234 */
77235ol.source.Raster.getImageData_ = function(renderer, frameState, layerState) {
77236 if (!renderer.prepareFrame(frameState, layerState)) {
77237 return null;
77238 }
77239 var width = frameState.size[0];
77240 var height = frameState.size[1];
77241 if (!ol.source.Raster.context_) {
77242 ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
77243 } else {
77244 var canvas = ol.source.Raster.context_.canvas;
77245 if (canvas.width !== width || canvas.height !== height) {
77246 ol.source.Raster.context_ = ol.dom.createCanvasContext2D(width, height);
77247 } else {
77248 ol.source.Raster.context_.clearRect(0, 0, width, height);
77249 }
77250 }
77251 renderer.composeFrame(frameState, layerState, ol.source.Raster.context_);
77252 return ol.source.Raster.context_.getImageData(0, 0, width, height);
77253};
77254
77255
77256/**
77257 * A reusable canvas context.
77258 * @type {CanvasRenderingContext2D}
77259 * @private
77260 */
77261ol.source.Raster.context_ = null;
77262
77263
77264/**
77265 * Get a list of layer states from a list of renderers.
77266 * @param {Array.<ol.renderer.canvas.Layer>} renderers Layer renderers.
77267 * @return {Array.<ol.LayerState>} The layer states.
77268 * @private
77269 */
77270ol.source.Raster.getLayerStatesArray_ = function(renderers) {
77271 return renderers.map(function(renderer) {
77272 return renderer.getLayer().getLayerState();
77273 });
77274};
77275
77276
77277/**
77278 * Create renderers for all sources.
77279 * @param {Array.<ol.source.Source>} sources The sources.
77280 * @return {Array.<ol.renderer.canvas.Layer>} Array of layer renderers.
77281 * @private
77282 */
77283ol.source.Raster.createRenderers_ = function(sources) {
77284 var len = sources.length;
77285 var renderers = new Array(len);
77286 for (var i = 0; i < len; ++i) {
77287 renderers[i] = ol.source.Raster.createRenderer_(sources[i]);
77288 }
77289 return renderers;
77290};
77291
77292
77293/**
77294 * Create a renderer for the provided source.
77295 * @param {ol.source.Source} source The source.
77296 * @return {ol.renderer.canvas.Layer} The renderer.
77297 * @private
77298 */
77299ol.source.Raster.createRenderer_ = function(source) {
77300 var renderer = null;
77301 if (source instanceof ol.source.Tile) {
77302 renderer = ol.source.Raster.createTileRenderer_(source);
77303 } else if (source instanceof ol.source.Image) {
77304 renderer = ol.source.Raster.createImageRenderer_(source);
77305 }
77306 return renderer;
77307};
77308
77309
77310/**
77311 * Create an image renderer for the provided source.
77312 * @param {ol.source.Image} source The source.
77313 * @return {ol.renderer.canvas.Layer} The renderer.
77314 * @private
77315 */
77316ol.source.Raster.createImageRenderer_ = function(source) {
77317 var layer = new ol.layer.Image({source: source});
77318 return new ol.renderer.canvas.ImageLayer(layer);
77319};
77320
77321
77322/**
77323 * Create a tile renderer for the provided source.
77324 * @param {ol.source.Tile} source The source.
77325 * @return {ol.renderer.canvas.Layer} The renderer.
77326 * @private
77327 */
77328ol.source.Raster.createTileRenderer_ = function(source) {
77329 var layer = new ol.layer.Tile({source: source});
77330 return new ol.renderer.canvas.TileLayer(layer);
77331};
77332
77333
77334/**
77335 * @classdesc
77336 * Events emitted by {@link ol.source.Raster} instances are instances of this
77337 * type.
77338 *
77339 * @constructor
77340 * @extends {ol.events.Event}
77341 * @implements {oli.source.RasterEvent}
77342 * @param {string} type Type.
77343 * @param {olx.FrameState} frameState The frame state.
77344 * @param {Object} data An object made available to operations.
77345 */
77346ol.source.Raster.Event = function(type, frameState, data) {
77347 ol.events.Event.call(this, type);
77348
77349 /**
77350 * The raster extent.
77351 * @type {ol.Extent}
77352 * @api
77353 */
77354 this.extent = frameState.extent;
77355
77356 /**
77357 * The pixel resolution (map units per pixel).
77358 * @type {number}
77359 * @api
77360 */
77361 this.resolution = frameState.viewState.resolution / frameState.pixelRatio;
77362
77363 /**
77364 * An object made available to all operations. This can be used by operations
77365 * as a storage object (e.g. for calculating statistics).
77366 * @type {Object}
77367 * @api
77368 */
77369 this.data = data;
77370
77371};
77372ol.inherits(ol.source.Raster.Event, ol.events.Event);
77373
77374
77375/**
77376 * @override
77377 */
77378ol.source.Raster.prototype.getImageInternal = function() {
77379 return null; // not implemented
77380};
77381
77382
77383/**
77384 * @enum {string}
77385 * @private
77386 */
77387ol.source.Raster.EventType_ = {
77388 /**
77389 * Triggered before operations are run.
77390 * @event ol.source.Raster.Event#beforeoperations
77391 * @api
77392 */
77393 BEFOREOPERATIONS: 'beforeoperations',
77394
77395 /**
77396 * Triggered after operations are run.
77397 * @event ol.source.Raster.Event#afteroperations
77398 * @api
77399 */
77400 AFTEROPERATIONS: 'afteroperations'
77401};
77402
77403goog.provide('ol.source.Stamen');
77404
77405goog.require('ol');
77406goog.require('ol.Attribution');
77407goog.require('ol.source.OSM');
77408goog.require('ol.source.XYZ');
77409
77410
77411/**
77412 * @classdesc
77413 * Layer source for the Stamen tile server.
77414 *
77415 * @constructor
77416 * @extends {ol.source.XYZ}
77417 * @param {olx.source.StamenOptions} options Stamen options.
77418 * @api
77419 */
77420ol.source.Stamen = function(options) {
77421 var i = options.layer.indexOf('-');
77422 var provider = i == -1 ? options.layer : options.layer.slice(0, i);
77423 var providerConfig = ol.source.Stamen.ProviderConfig[provider];
77424
77425 var layerConfig = ol.source.Stamen.LayerConfig[options.layer];
77426
77427 var url = options.url !== undefined ? options.url :
77428 'https://stamen-tiles-{a-d}.a.ssl.fastly.net/' + options.layer +
77429 '/{z}/{x}/{y}.' + layerConfig.extension;
77430
77431 ol.source.XYZ.call(this, {
77432 attributions: ol.source.Stamen.ATTRIBUTIONS,
77433 cacheSize: options.cacheSize,
77434 crossOrigin: 'anonymous',
77435 maxZoom: options.maxZoom != undefined ? options.maxZoom : providerConfig.maxZoom,
77436 minZoom: options.minZoom != undefined ? options.minZoom : providerConfig.minZoom,
77437 opaque: layerConfig.opaque,
77438 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
77439 tileLoadFunction: options.tileLoadFunction,
77440 url: url,
77441 wrapX: options.wrapX
77442 });
77443};
77444ol.inherits(ol.source.Stamen, ol.source.XYZ);
77445
77446
77447/**
77448 * @const
77449 * @type {Array.<ol.Attribution>}
77450 */
77451ol.source.Stamen.ATTRIBUTIONS = [
77452 new ol.Attribution({
77453 html: 'Map tiles by <a href="https://stamen.com/">Stamen Design</a>, ' +
77454 'under <a href="https://creativecommons.org/licenses/by/3.0/">CC BY' +
77455 ' 3.0</a>.'
77456 }),
77457 ol.source.OSM.ATTRIBUTION
77458];
77459
77460/**
77461 * @type {Object.<string, {extension: string, opaque: boolean}>}
77462 */
77463ol.source.Stamen.LayerConfig = {
77464 'terrain': {
77465 extension: 'jpg',
77466 opaque: true
77467 },
77468 'terrain-background': {
77469 extension: 'jpg',
77470 opaque: true
77471 },
77472 'terrain-labels': {
77473 extension: 'png',
77474 opaque: false
77475 },
77476 'terrain-lines': {
77477 extension: 'png',
77478 opaque: false
77479 },
77480 'toner-background': {
77481 extension: 'png',
77482 opaque: true
77483 },
77484 'toner': {
77485 extension: 'png',
77486 opaque: true
77487 },
77488 'toner-hybrid': {
77489 extension: 'png',
77490 opaque: false
77491 },
77492 'toner-labels': {
77493 extension: 'png',
77494 opaque: false
77495 },
77496 'toner-lines': {
77497 extension: 'png',
77498 opaque: false
77499 },
77500 'toner-lite': {
77501 extension: 'png',
77502 opaque: true
77503 },
77504 'watercolor': {
77505 extension: 'jpg',
77506 opaque: true
77507 }
77508};
77509
77510/**
77511 * @type {Object.<string, {minZoom: number, maxZoom: number}>}
77512 */
77513ol.source.Stamen.ProviderConfig = {
77514 'terrain': {
77515 minZoom: 4,
77516 maxZoom: 18
77517 },
77518 'toner': {
77519 minZoom: 0,
77520 maxZoom: 20
77521 },
77522 'watercolor': {
77523 minZoom: 1,
77524 maxZoom: 16
77525 }
77526};
77527
77528goog.provide('ol.source.TileArcGISRest');
77529
77530goog.require('ol');
77531goog.require('ol.extent');
77532goog.require('ol.math');
77533goog.require('ol.obj');
77534goog.require('ol.size');
77535goog.require('ol.source.TileImage');
77536goog.require('ol.tilecoord');
77537goog.require('ol.uri');
77538
77539
77540/**
77541 * @classdesc
77542 * Layer source for tile data from ArcGIS Rest services. Map and Image
77543 * Services are supported.
77544 *
77545 * For cached ArcGIS services, better performance is available using the
77546 * {@link ol.source.XYZ} data source.
77547 *
77548 * @constructor
77549 * @extends {ol.source.TileImage}
77550 * @param {olx.source.TileArcGISRestOptions=} opt_options Tile ArcGIS Rest
77551 * options.
77552 * @api
77553 */
77554ol.source.TileArcGISRest = function(opt_options) {
77555
77556 var options = opt_options || {};
77557
77558 ol.source.TileImage.call(this, {
77559 attributions: options.attributions,
77560 cacheSize: options.cacheSize,
77561 crossOrigin: options.crossOrigin,
77562 logo: options.logo,
77563 projection: options.projection,
77564 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
77565 tileGrid: options.tileGrid,
77566 tileLoadFunction: options.tileLoadFunction,
77567 url: options.url,
77568 urls: options.urls,
77569 wrapX: options.wrapX !== undefined ? options.wrapX : true
77570 });
77571
77572 /**
77573 * @private
77574 * @type {!Object}
77575 */
77576 this.params_ = options.params || {};
77577
77578 /**
77579 * @private
77580 * @type {ol.Extent}
77581 */
77582 this.tmpExtent_ = ol.extent.createEmpty();
77583
77584 this.setKey(this.getKeyForParams_());
77585};
77586ol.inherits(ol.source.TileArcGISRest, ol.source.TileImage);
77587
77588
77589/**
77590 * @private
77591 * @return {string} The key for the current params.
77592 */
77593ol.source.TileArcGISRest.prototype.getKeyForParams_ = function() {
77594 var i = 0;
77595 var res = [];
77596 for (var key in this.params_) {
77597 res[i++] = key + '-' + this.params_[key];
77598 }
77599 return res.join('/');
77600};
77601
77602
77603/**
77604 * Get the user-provided params, i.e. those passed to the constructor through
77605 * the "params" option, and possibly updated using the updateParams method.
77606 * @return {Object} Params.
77607 * @api
77608 */
77609ol.source.TileArcGISRest.prototype.getParams = function() {
77610 return this.params_;
77611};
77612
77613
77614/**
77615 * @param {ol.TileCoord} tileCoord Tile coordinate.
77616 * @param {ol.Size} tileSize Tile size.
77617 * @param {ol.Extent} tileExtent Tile extent.
77618 * @param {number} pixelRatio Pixel ratio.
77619 * @param {ol.proj.Projection} projection Projection.
77620 * @param {Object} params Params.
77621 * @return {string|undefined} Request URL.
77622 * @private
77623 */
77624ol.source.TileArcGISRest.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,
77625 pixelRatio, projection, params) {
77626
77627 var urls = this.urls;
77628 if (!urls) {
77629 return undefined;
77630 }
77631
77632 // ArcGIS Server only wants the numeric portion of the projection ID.
77633 var srid = projection.getCode().split(':').pop();
77634
77635 params['SIZE'] = tileSize[0] + ',' + tileSize[1];
77636 params['BBOX'] = tileExtent.join(',');
77637 params['BBOXSR'] = srid;
77638 params['IMAGESR'] = srid;
77639 params['DPI'] = Math.round(
77640 params['DPI'] ? params['DPI'] * pixelRatio : 90 * pixelRatio
77641 );
77642
77643 var url;
77644 if (urls.length == 1) {
77645 url = urls[0];
77646 } else {
77647 var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);
77648 url = urls[index];
77649 }
77650
77651 var modifiedUrl = url
77652 .replace(/MapServer\/?$/, 'MapServer/export')
77653 .replace(/ImageServer\/?$/, 'ImageServer/exportImage');
77654 return ol.uri.appendParams(modifiedUrl, params);
77655};
77656
77657
77658/**
77659 * @inheritDoc
77660 */
77661ol.source.TileArcGISRest.prototype.getTilePixelRatio = function(pixelRatio) {
77662 return /** @type {number} */ (pixelRatio);
77663};
77664
77665
77666/**
77667 * @inheritDoc
77668 */
77669ol.source.TileArcGISRest.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {
77670
77671 var tileGrid = this.getTileGrid();
77672 if (!tileGrid) {
77673 tileGrid = this.getTileGridForProjection(projection);
77674 }
77675
77676 if (tileGrid.getResolutions().length <= tileCoord[0]) {
77677 return undefined;
77678 }
77679
77680 var tileExtent = tileGrid.getTileCoordExtent(
77681 tileCoord, this.tmpExtent_);
77682 var tileSize = ol.size.toSize(
77683 tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
77684
77685 if (pixelRatio != 1) {
77686 tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);
77687 }
77688
77689 // Apply default params and override with user specified values.
77690 var baseParams = {
77691 'F': 'image',
77692 'FORMAT': 'PNG32',
77693 'TRANSPARENT': true
77694 };
77695 ol.obj.assign(baseParams, this.params_);
77696
77697 return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
77698 pixelRatio, projection, baseParams);
77699};
77700
77701
77702/**
77703 * Update the user-provided params.
77704 * @param {Object} params Params.
77705 * @api
77706 */
77707ol.source.TileArcGISRest.prototype.updateParams = function(params) {
77708 ol.obj.assign(this.params_, params);
77709 this.setKey(this.getKeyForParams_());
77710};
77711
77712goog.provide('ol.source.TileDebug');
77713
77714goog.require('ol');
77715goog.require('ol.Tile');
77716goog.require('ol.TileState');
77717goog.require('ol.dom');
77718goog.require('ol.size');
77719goog.require('ol.source.Tile');
77720
77721
77722/**
77723 * @classdesc
77724 * A pseudo tile source, which does not fetch tiles from a server, but renders
77725 * a grid outline for the tile grid/projection along with the coordinates for
77726 * each tile. See examples/canvas-tiles for an example.
77727 *
77728 * Uses Canvas context2d, so requires Canvas support.
77729 *
77730 * @constructor
77731 * @extends {ol.source.Tile}
77732 * @param {olx.source.TileDebugOptions} options Debug tile options.
77733 * @api
77734 */
77735ol.source.TileDebug = function(options) {
77736
77737 ol.source.Tile.call(this, {
77738 opaque: false,
77739 projection: options.projection,
77740 tileGrid: options.tileGrid,
77741 wrapX: options.wrapX !== undefined ? options.wrapX : true
77742 });
77743
77744};
77745ol.inherits(ol.source.TileDebug, ol.source.Tile);
77746
77747
77748/**
77749 * @inheritDoc
77750 */
77751ol.source.TileDebug.prototype.getTile = function(z, x, y) {
77752 var tileCoordKey = this.getKeyZXY(z, x, y);
77753 if (this.tileCache.containsKey(tileCoordKey)) {
77754 return /** @type {!ol.source.TileDebug.Tile_} */ (this.tileCache.get(tileCoordKey));
77755 } else {
77756 var tileSize = ol.size.toSize(this.tileGrid.getTileSize(z));
77757 var tileCoord = [z, x, y];
77758 var textTileCoord = this.getTileCoordForTileUrlFunction(tileCoord);
77759 var text = !textTileCoord ? '' :
77760 this.getTileCoordForTileUrlFunction(textTileCoord).toString();
77761 var tile = new ol.source.TileDebug.Tile_(tileCoord, tileSize, text);
77762 this.tileCache.set(tileCoordKey, tile);
77763 return tile;
77764 }
77765};
77766
77767
77768/**
77769 * @constructor
77770 * @extends {ol.Tile}
77771 * @param {ol.TileCoord} tileCoord Tile coordinate.
77772 * @param {ol.Size} tileSize Tile size.
77773 * @param {string} text Text.
77774 * @private
77775 */
77776ol.source.TileDebug.Tile_ = function(tileCoord, tileSize, text) {
77777
77778 ol.Tile.call(this, tileCoord, ol.TileState.LOADED);
77779
77780 /**
77781 * @private
77782 * @type {ol.Size}
77783 */
77784 this.tileSize_ = tileSize;
77785
77786 /**
77787 * @private
77788 * @type {string}
77789 */
77790 this.text_ = text;
77791
77792 /**
77793 * @private
77794 * @type {HTMLCanvasElement}
77795 */
77796 this.canvas_ = null;
77797
77798};
77799ol.inherits(ol.source.TileDebug.Tile_, ol.Tile);
77800
77801
77802/**
77803 * Get the image element for this tile.
77804 * @return {HTMLCanvasElement} Image.
77805 */
77806ol.source.TileDebug.Tile_.prototype.getImage = function() {
77807 if (this.canvas_) {
77808 return this.canvas_;
77809 } else {
77810 var tileSize = this.tileSize_;
77811 var context = ol.dom.createCanvasContext2D(tileSize[0], tileSize[1]);
77812
77813 context.strokeStyle = 'black';
77814 context.strokeRect(0.5, 0.5, tileSize[0] + 0.5, tileSize[1] + 0.5);
77815
77816 context.fillStyle = 'black';
77817 context.textAlign = 'center';
77818 context.textBaseline = 'middle';
77819 context.font = '24px sans-serif';
77820 context.fillText(this.text_, tileSize[0] / 2, tileSize[1] / 2);
77821
77822 this.canvas_ = context.canvas;
77823 return context.canvas;
77824 }
77825};
77826
77827
77828/**
77829 * @override
77830 */
77831ol.source.TileDebug.Tile_.prototype.load = function() {};
77832
77833// FIXME check order of async callbacks
77834
77835/**
77836 * @see http://mapbox.com/developers/api/
77837 */
77838
77839goog.provide('ol.source.TileJSON');
77840
77841goog.require('ol');
77842goog.require('ol.Attribution');
77843goog.require('ol.TileUrlFunction');
77844goog.require('ol.asserts');
77845goog.require('ol.extent');
77846goog.require('ol.net');
77847goog.require('ol.proj');
77848goog.require('ol.source.State');
77849goog.require('ol.source.TileImage');
77850goog.require('ol.tilegrid');
77851
77852
77853/**
77854 * @classdesc
77855 * Layer source for tile data in TileJSON format.
77856 *
77857 * @constructor
77858 * @extends {ol.source.TileImage}
77859 * @param {olx.source.TileJSONOptions} options TileJSON options.
77860 * @api
77861 */
77862ol.source.TileJSON = function(options) {
77863
77864 /**
77865 * @type {TileJSON}
77866 * @private
77867 */
77868 this.tileJSON_ = null;
77869
77870 ol.source.TileImage.call(this, {
77871 attributions: options.attributions,
77872 cacheSize: options.cacheSize,
77873 crossOrigin: options.crossOrigin,
77874 projection: ol.proj.get('EPSG:3857'),
77875 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
77876 state: ol.source.State.LOADING,
77877 tileLoadFunction: options.tileLoadFunction,
77878 wrapX: options.wrapX !== undefined ? options.wrapX : true
77879 });
77880
77881 if (options.url) {
77882 if (options.jsonp) {
77883 ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
77884 this.handleTileJSONError.bind(this));
77885 } else {
77886 var client = new XMLHttpRequest();
77887 client.addEventListener('load', this.onXHRLoad_.bind(this));
77888 client.addEventListener('error', this.onXHRError_.bind(this));
77889 client.open('GET', options.url);
77890 client.send();
77891 }
77892 } else if (options.tileJSON) {
77893 this.handleTileJSONResponse(options.tileJSON);
77894 } else {
77895 ol.asserts.assert(false, 51); // Either `url` or `tileJSON` options must be provided
77896 }
77897
77898};
77899ol.inherits(ol.source.TileJSON, ol.source.TileImage);
77900
77901
77902/**
77903 * @private
77904 * @param {Event} event The load event.
77905 */
77906ol.source.TileJSON.prototype.onXHRLoad_ = function(event) {
77907 var client = /** @type {XMLHttpRequest} */ (event.target);
77908 // status will be 0 for file:// urls
77909 if (!client.status || client.status >= 200 && client.status < 300) {
77910 var response;
77911 try {
77912 response = /** @type {TileJSON} */(JSON.parse(client.responseText));
77913 } catch (err) {
77914 this.handleTileJSONError();
77915 return;
77916 }
77917 this.handleTileJSONResponse(response);
77918 } else {
77919 this.handleTileJSONError();
77920 }
77921};
77922
77923
77924/**
77925 * @private
77926 * @param {Event} event The error event.
77927 */
77928ol.source.TileJSON.prototype.onXHRError_ = function(event) {
77929 this.handleTileJSONError();
77930};
77931
77932
77933/**
77934 * @return {TileJSON} The tilejson object.
77935 * @api
77936 */
77937ol.source.TileJSON.prototype.getTileJSON = function() {
77938 return this.tileJSON_;
77939};
77940
77941
77942/**
77943 * @protected
77944 * @param {TileJSON} tileJSON Tile JSON.
77945 */
77946ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
77947
77948 var epsg4326Projection = ol.proj.get('EPSG:4326');
77949
77950 var sourceProjection = this.getProjection();
77951 var extent;
77952 if (tileJSON.bounds !== undefined) {
77953 var transform = ol.proj.getTransformFromProjections(
77954 epsg4326Projection, sourceProjection);
77955 extent = ol.extent.applyTransform(tileJSON.bounds, transform);
77956 }
77957
77958 var minZoom = tileJSON.minzoom || 0;
77959 var maxZoom = tileJSON.maxzoom || 22;
77960 var tileGrid = ol.tilegrid.createXYZ({
77961 extent: ol.tilegrid.extentFromProjection(sourceProjection),
77962 maxZoom: maxZoom,
77963 minZoom: minZoom
77964 });
77965 this.tileGrid = tileGrid;
77966
77967 this.tileUrlFunction =
77968 ol.TileUrlFunction.createFromTemplates(tileJSON.tiles, tileGrid);
77969
77970 if (tileJSON.attribution !== undefined && !this.getAttributions()) {
77971 var attributionExtent = extent !== undefined ?
77972 extent : epsg4326Projection.getExtent();
77973 /** @type {Object.<string, Array.<ol.TileRange>>} */
77974 var tileRanges = {};
77975 var z, zKey;
77976 for (z = minZoom; z <= maxZoom; ++z) {
77977 zKey = z.toString();
77978 tileRanges[zKey] =
77979 [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
77980 }
77981 this.setAttributions([
77982 new ol.Attribution({
77983 html: tileJSON.attribution,
77984 tileRanges: tileRanges
77985 })
77986 ]);
77987 }
77988 this.tileJSON_ = tileJSON;
77989 this.setState(ol.source.State.READY);
77990
77991};
77992
77993
77994/**
77995 * @protected
77996 */
77997ol.source.TileJSON.prototype.handleTileJSONError = function() {
77998 this.setState(ol.source.State.ERROR);
77999};
78000
78001goog.provide('ol.source.TileUTFGrid');
78002
78003goog.require('ol');
78004goog.require('ol.Attribution');
78005goog.require('ol.Tile');
78006goog.require('ol.TileState');
78007goog.require('ol.TileUrlFunction');
78008goog.require('ol.asserts');
78009goog.require('ol.events');
78010goog.require('ol.events.EventType');
78011goog.require('ol.extent');
78012goog.require('ol.net');
78013goog.require('ol.proj');
78014goog.require('ol.source.State');
78015goog.require('ol.source.Tile');
78016goog.require('ol.tilegrid');
78017
78018
78019/**
78020 * @classdesc
78021 * Layer source for UTFGrid interaction data loaded from TileJSON format.
78022 *
78023 * @constructor
78024 * @extends {ol.source.Tile}
78025 * @param {olx.source.TileUTFGridOptions} options Source options.
78026 * @api
78027 */
78028ol.source.TileUTFGrid = function(options) {
78029 ol.source.Tile.call(this, {
78030 projection: ol.proj.get('EPSG:3857'),
78031 state: ol.source.State.LOADING
78032 });
78033
78034 /**
78035 * @private
78036 * @type {boolean}
78037 */
78038 this.preemptive_ = options.preemptive !== undefined ?
78039 options.preemptive : true;
78040
78041 /**
78042 * @private
78043 * @type {!ol.TileUrlFunctionType}
78044 */
78045 this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;
78046
78047 /**
78048 * @private
78049 * @type {string|undefined}
78050 */
78051 this.template_ = undefined;
78052
78053 /**
78054 * @private
78055 * @type {boolean}
78056 */
78057 this.jsonp_ = options.jsonp || false;
78058
78059 if (options.url) {
78060 if (this.jsonp_) {
78061 ol.net.jsonp(options.url, this.handleTileJSONResponse.bind(this),
78062 this.handleTileJSONError.bind(this));
78063 } else {
78064 var client = new XMLHttpRequest();
78065 client.addEventListener('load', this.onXHRLoad_.bind(this));
78066 client.addEventListener('error', this.onXHRError_.bind(this));
78067 client.open('GET', options.url);
78068 client.send();
78069 }
78070 } else if (options.tileJSON) {
78071 this.handleTileJSONResponse(options.tileJSON);
78072 } else {
78073 ol.asserts.assert(false, 51); // Either `url` or `tileJSON` options must be provided
78074 }
78075};
78076ol.inherits(ol.source.TileUTFGrid, ol.source.Tile);
78077
78078
78079/**
78080 * @private
78081 * @param {Event} event The load event.
78082 */
78083ol.source.TileUTFGrid.prototype.onXHRLoad_ = function(event) {
78084 var client = /** @type {XMLHttpRequest} */ (event.target);
78085 // status will be 0 for file:// urls
78086 if (!client.status || client.status >= 200 && client.status < 300) {
78087 var response;
78088 try {
78089 response = /** @type {TileJSON} */(JSON.parse(client.responseText));
78090 } catch (err) {
78091 this.handleTileJSONError();
78092 return;
78093 }
78094 this.handleTileJSONResponse(response);
78095 } else {
78096 this.handleTileJSONError();
78097 }
78098};
78099
78100
78101/**
78102 * @private
78103 * @param {Event} event The error event.
78104 */
78105ol.source.TileUTFGrid.prototype.onXHRError_ = function(event) {
78106 this.handleTileJSONError();
78107};
78108
78109
78110/**
78111 * Return the template from TileJSON.
78112 * @return {string|undefined} The template from TileJSON.
78113 * @api
78114 */
78115ol.source.TileUTFGrid.prototype.getTemplate = function() {
78116 return this.template_;
78117};
78118
78119
78120/**
78121 * Calls the callback (synchronously by default) with the available data
78122 * for given coordinate and resolution (or `null` if not yet loaded or
78123 * in case of an error).
78124 * @param {ol.Coordinate} coordinate Coordinate.
78125 * @param {number} resolution Resolution.
78126 * @param {function(this: T, *)} callback Callback.
78127 * @param {T=} opt_this The object to use as `this` in the callback.
78128 * @param {boolean=} opt_request If `true` the callback is always async.
78129 * The tile data is requested if not yet loaded.
78130 * @template T
78131 * @api
78132 */
78133ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution = function(
78134 coordinate, resolution, callback, opt_this, opt_request) {
78135 if (this.tileGrid) {
78136 var tileCoord = this.tileGrid.getTileCoordForCoordAndResolution(
78137 coordinate, resolution);
78138 var tile = /** @type {!ol.source.TileUTFGrid.Tile_} */(this.getTile(
78139 tileCoord[0], tileCoord[1], tileCoord[2], 1, this.getProjection()));
78140 tile.forDataAtCoordinate(coordinate, callback, opt_this, opt_request);
78141 } else {
78142 if (opt_request === true) {
78143 setTimeout(function() {
78144 callback.call(opt_this, null);
78145 }, 0);
78146 } else {
78147 callback.call(opt_this, null);
78148 }
78149 }
78150};
78151
78152
78153/**
78154 * @protected
78155 */
78156ol.source.TileUTFGrid.prototype.handleTileJSONError = function() {
78157 this.setState(ol.source.State.ERROR);
78158};
78159
78160
78161/**
78162 * TODO: very similar to ol.source.TileJSON#handleTileJSONResponse
78163 * @protected
78164 * @param {TileJSON} tileJSON Tile JSON.
78165 */
78166ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
78167
78168 var epsg4326Projection = ol.proj.get('EPSG:4326');
78169
78170 var sourceProjection = this.getProjection();
78171 var extent;
78172 if (tileJSON.bounds !== undefined) {
78173 var transform = ol.proj.getTransformFromProjections(
78174 epsg4326Projection, sourceProjection);
78175 extent = ol.extent.applyTransform(tileJSON.bounds, transform);
78176 }
78177
78178 var minZoom = tileJSON.minzoom || 0;
78179 var maxZoom = tileJSON.maxzoom || 22;
78180 var tileGrid = ol.tilegrid.createXYZ({
78181 extent: ol.tilegrid.extentFromProjection(sourceProjection),
78182 maxZoom: maxZoom,
78183 minZoom: minZoom
78184 });
78185 this.tileGrid = tileGrid;
78186
78187 this.template_ = tileJSON.template;
78188
78189 var grids = tileJSON.grids;
78190 if (!grids) {
78191 this.setState(ol.source.State.ERROR);
78192 return;
78193 }
78194
78195 this.tileUrlFunction_ =
78196 ol.TileUrlFunction.createFromTemplates(grids, tileGrid);
78197
78198 if (tileJSON.attribution !== undefined) {
78199 var attributionExtent = extent !== undefined ?
78200 extent : epsg4326Projection.getExtent();
78201 /** @type {Object.<string, Array.<ol.TileRange>>} */
78202 var tileRanges = {};
78203 var z, zKey;
78204 for (z = minZoom; z <= maxZoom; ++z) {
78205 zKey = z.toString();
78206 tileRanges[zKey] =
78207 [tileGrid.getTileRangeForExtentAndZ(attributionExtent, z)];
78208 }
78209 this.setAttributions([
78210 new ol.Attribution({
78211 html: tileJSON.attribution,
78212 tileRanges: tileRanges
78213 })
78214 ]);
78215 }
78216
78217 this.setState(ol.source.State.READY);
78218
78219};
78220
78221
78222/**
78223 * @inheritDoc
78224 */
78225ol.source.TileUTFGrid.prototype.getTile = function(z, x, y, pixelRatio, projection) {
78226 var tileCoordKey = this.getKeyZXY(z, x, y);
78227 if (this.tileCache.containsKey(tileCoordKey)) {
78228 return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
78229 } else {
78230 var tileCoord = [z, x, y];
78231 var urlTileCoord =
78232 this.getTileCoordForTileUrlFunction(tileCoord, projection);
78233 var tileUrl = this.tileUrlFunction_(urlTileCoord, pixelRatio, projection);
78234 var tile = new ol.source.TileUTFGrid.Tile_(
78235 tileCoord,
78236 tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
78237 tileUrl !== undefined ? tileUrl : '',
78238 this.tileGrid.getTileCoordExtent(tileCoord),
78239 this.preemptive_,
78240 this.jsonp_);
78241 this.tileCache.set(tileCoordKey, tile);
78242 return tile;
78243 }
78244};
78245
78246
78247/**
78248 * @inheritDoc
78249 */
78250ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {
78251 var tileCoordKey = this.getKeyZXY(z, x, y);
78252 if (this.tileCache.containsKey(tileCoordKey)) {
78253 this.tileCache.get(tileCoordKey);
78254 }
78255};
78256
78257
78258/**
78259 * @constructor
78260 * @extends {ol.Tile}
78261 * @param {ol.TileCoord} tileCoord Tile coordinate.
78262 * @param {ol.TileState} state State.
78263 * @param {string} src Image source URI.
78264 * @param {ol.Extent} extent Extent of the tile.
78265 * @param {boolean} preemptive Load the tile when visible (before it's needed).
78266 * @param {boolean} jsonp Load the tile as a script.
78267 * @private
78268 */
78269ol.source.TileUTFGrid.Tile_ = function(tileCoord, state, src, extent, preemptive, jsonp) {
78270
78271 ol.Tile.call(this, tileCoord, state);
78272
78273 /**
78274 * @private
78275 * @type {string}
78276 */
78277 this.src_ = src;
78278
78279 /**
78280 * @private
78281 * @type {ol.Extent}
78282 */
78283 this.extent_ = extent;
78284
78285 /**
78286 * @private
78287 * @type {boolean}
78288 */
78289 this.preemptive_ = preemptive;
78290
78291 /**
78292 * @private
78293 * @type {Array.<string>}
78294 */
78295 this.grid_ = null;
78296
78297 /**
78298 * @private
78299 * @type {Array.<string>}
78300 */
78301 this.keys_ = null;
78302
78303 /**
78304 * @private
78305 * @type {Object.<string, Object>|undefined}
78306 */
78307 this.data_ = null;
78308
78309
78310 /**
78311 * @private
78312 * @type {boolean}
78313 */
78314 this.jsonp_ = jsonp;
78315
78316};
78317ol.inherits(ol.source.TileUTFGrid.Tile_, ol.Tile);
78318
78319
78320/**
78321 * Get the image element for this tile.
78322 * @return {Image} Image.
78323 */
78324ol.source.TileUTFGrid.Tile_.prototype.getImage = function() {
78325 return null;
78326};
78327
78328
78329/**
78330 * Synchronously returns data at given coordinate (if available).
78331 * @param {ol.Coordinate} coordinate Coordinate.
78332 * @return {*} The data.
78333 */
78334ol.source.TileUTFGrid.Tile_.prototype.getData = function(coordinate) {
78335 if (!this.grid_ || !this.keys_) {
78336 return null;
78337 }
78338 var xRelative = (coordinate[0] - this.extent_[0]) /
78339 (this.extent_[2] - this.extent_[0]);
78340 var yRelative = (coordinate[1] - this.extent_[1]) /
78341 (this.extent_[3] - this.extent_[1]);
78342
78343 var row = this.grid_[Math.floor((1 - yRelative) * this.grid_.length)];
78344
78345 if (typeof row !== 'string') {
78346 return null;
78347 }
78348
78349 var code = row.charCodeAt(Math.floor(xRelative * row.length));
78350 if (code >= 93) {
78351 code--;
78352 }
78353 if (code >= 35) {
78354 code--;
78355 }
78356 code -= 32;
78357
78358 var data = null;
78359 if (code in this.keys_) {
78360 var id = this.keys_[code];
78361 if (this.data_ && id in this.data_) {
78362 data = this.data_[id];
78363 } else {
78364 data = id;
78365 }
78366 }
78367 return data;
78368};
78369
78370
78371/**
78372 * Calls the callback (synchronously by default) with the available data
78373 * for given coordinate (or `null` if not yet loaded).
78374 * @param {ol.Coordinate} coordinate Coordinate.
78375 * @param {function(this: T, *)} callback Callback.
78376 * @param {T=} opt_this The object to use as `this` in the callback.
78377 * @param {boolean=} opt_request If `true` the callback is always async.
78378 * The tile data is requested if not yet loaded.
78379 * @template T
78380 */
78381ol.source.TileUTFGrid.Tile_.prototype.forDataAtCoordinate = function(coordinate, callback, opt_this, opt_request) {
78382 if (this.state == ol.TileState.IDLE && opt_request === true) {
78383 ol.events.listenOnce(this, ol.events.EventType.CHANGE, function(e) {
78384 callback.call(opt_this, this.getData(coordinate));
78385 }, this);
78386 this.loadInternal_();
78387 } else {
78388 if (opt_request === true) {
78389 setTimeout(function() {
78390 callback.call(opt_this, this.getData(coordinate));
78391 }.bind(this), 0);
78392 } else {
78393 callback.call(opt_this, this.getData(coordinate));
78394 }
78395 }
78396};
78397
78398
78399/**
78400 * @inheritDoc
78401 */
78402ol.source.TileUTFGrid.Tile_.prototype.getKey = function() {
78403 return this.src_;
78404};
78405
78406
78407/**
78408 * @private
78409 */
78410ol.source.TileUTFGrid.Tile_.prototype.handleError_ = function() {
78411 this.state = ol.TileState.ERROR;
78412 this.changed();
78413};
78414
78415
78416/**
78417 * @param {!UTFGridJSON} json UTFGrid data.
78418 * @private
78419 */
78420ol.source.TileUTFGrid.Tile_.prototype.handleLoad_ = function(json) {
78421 this.grid_ = json.grid;
78422 this.keys_ = json.keys;
78423 this.data_ = json.data;
78424
78425 this.state = ol.TileState.EMPTY;
78426 this.changed();
78427};
78428
78429
78430/**
78431 * @private
78432 */
78433ol.source.TileUTFGrid.Tile_.prototype.loadInternal_ = function() {
78434 if (this.state == ol.TileState.IDLE) {
78435 this.state = ol.TileState.LOADING;
78436 if (this.jsonp_) {
78437 ol.net.jsonp(this.src_, this.handleLoad_.bind(this),
78438 this.handleError_.bind(this));
78439 } else {
78440 var client = new XMLHttpRequest();
78441 client.addEventListener('load', this.onXHRLoad_.bind(this));
78442 client.addEventListener('error', this.onXHRError_.bind(this));
78443 client.open('GET', this.src_);
78444 client.send();
78445 }
78446 }
78447};
78448
78449
78450/**
78451 * @private
78452 * @param {Event} event The load event.
78453 */
78454ol.source.TileUTFGrid.Tile_.prototype.onXHRLoad_ = function(event) {
78455 var client = /** @type {XMLHttpRequest} */ (event.target);
78456 // status will be 0 for file:// urls
78457 if (!client.status || client.status >= 200 && client.status < 300) {
78458 var response;
78459 try {
78460 response = /** @type {!UTFGridJSON} */(JSON.parse(client.responseText));
78461 } catch (err) {
78462 this.handleError_();
78463 return;
78464 }
78465 this.handleLoad_(response);
78466 } else {
78467 this.handleError_();
78468 }
78469};
78470
78471
78472/**
78473 * @private
78474 * @param {Event} event The error event.
78475 */
78476ol.source.TileUTFGrid.Tile_.prototype.onXHRError_ = function(event) {
78477 this.handleError_();
78478};
78479
78480
78481/**
78482 * @override
78483 */
78484ol.source.TileUTFGrid.Tile_.prototype.load = function() {
78485 if (this.preemptive_) {
78486 this.loadInternal_();
78487 }
78488};
78489
78490// FIXME add minZoom support
78491// FIXME add date line wrap (tile coord transform)
78492// FIXME cannot be shared between maps with different projections
78493
78494goog.provide('ol.source.TileWMS');
78495
78496goog.require('ol');
78497goog.require('ol.asserts');
78498goog.require('ol.extent');
78499goog.require('ol.obj');
78500goog.require('ol.math');
78501goog.require('ol.proj');
78502goog.require('ol.size');
78503goog.require('ol.source.TileImage');
78504goog.require('ol.source.WMSServerType');
78505goog.require('ol.tilecoord');
78506goog.require('ol.string');
78507goog.require('ol.uri');
78508
78509/**
78510 * @classdesc
78511 * Layer source for tile data from WMS servers.
78512 *
78513 * @constructor
78514 * @extends {ol.source.TileImage}
78515 * @param {olx.source.TileWMSOptions=} opt_options Tile WMS options.
78516 * @api
78517 */
78518ol.source.TileWMS = function(opt_options) {
78519
78520 var options = opt_options || {};
78521
78522 var params = options.params || {};
78523
78524 var transparent = 'TRANSPARENT' in params ? params['TRANSPARENT'] : true;
78525
78526 ol.source.TileImage.call(this, {
78527 attributions: options.attributions,
78528 cacheSize: options.cacheSize,
78529 crossOrigin: options.crossOrigin,
78530 logo: options.logo,
78531 opaque: !transparent,
78532 projection: options.projection,
78533 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
78534 tileClass: options.tileClass,
78535 tileGrid: options.tileGrid,
78536 tileLoadFunction: options.tileLoadFunction,
78537 url: options.url,
78538 urls: options.urls,
78539 wrapX: options.wrapX !== undefined ? options.wrapX : true
78540 });
78541
78542 /**
78543 * @private
78544 * @type {number}
78545 */
78546 this.gutter_ = options.gutter !== undefined ? options.gutter : 0;
78547
78548 /**
78549 * @private
78550 * @type {!Object}
78551 */
78552 this.params_ = params;
78553
78554 /**
78555 * @private
78556 * @type {boolean}
78557 */
78558 this.v13_ = true;
78559
78560 /**
78561 * @private
78562 * @type {ol.source.WMSServerType|undefined}
78563 */
78564 this.serverType_ = /** @type {ol.source.WMSServerType|undefined} */ (options.serverType);
78565
78566 /**
78567 * @private
78568 * @type {boolean}
78569 */
78570 this.hidpi_ = options.hidpi !== undefined ? options.hidpi : true;
78571
78572 /**
78573 * @private
78574 * @type {string}
78575 */
78576 this.coordKeyPrefix_ = '';
78577 this.resetCoordKeyPrefix_();
78578
78579 /**
78580 * @private
78581 * @type {ol.Extent}
78582 */
78583 this.tmpExtent_ = ol.extent.createEmpty();
78584
78585 this.updateV13_();
78586 this.setKey(this.getKeyForParams_());
78587
78588};
78589ol.inherits(ol.source.TileWMS, ol.source.TileImage);
78590
78591
78592/**
78593 * Return the GetFeatureInfo URL for the passed coordinate, resolution, and
78594 * projection. Return `undefined` if the GetFeatureInfo URL cannot be
78595 * constructed.
78596 * @param {ol.Coordinate} coordinate Coordinate.
78597 * @param {number} resolution Resolution.
78598 * @param {ol.ProjectionLike} projection Projection.
78599 * @param {!Object} params GetFeatureInfo params. `INFO_FORMAT` at least should
78600 * be provided. If `QUERY_LAYERS` is not provided then the layers specified
78601 * in the `LAYERS` parameter will be used. `VERSION` should not be
78602 * specified here.
78603 * @return {string|undefined} GetFeatureInfo URL.
78604 * @api
78605 */
78606ol.source.TileWMS.prototype.getGetFeatureInfoUrl = function(coordinate, resolution, projection, params) {
78607 var projectionObj = ol.proj.get(projection);
78608
78609 var tileGrid = this.getTileGrid();
78610 if (!tileGrid) {
78611 tileGrid = this.getTileGridForProjection(projectionObj);
78612 }
78613
78614 var tileCoord = tileGrid.getTileCoordForCoordAndResolution(
78615 coordinate, resolution);
78616
78617 if (tileGrid.getResolutions().length <= tileCoord[0]) {
78618 return undefined;
78619 }
78620
78621 var tileResolution = tileGrid.getResolution(tileCoord[0]);
78622 var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
78623 var tileSize = ol.size.toSize(
78624 tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
78625
78626 var gutter = this.gutter_;
78627 if (gutter !== 0) {
78628 tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
78629 tileExtent = ol.extent.buffer(tileExtent,
78630 tileResolution * gutter, tileExtent);
78631 }
78632
78633 var baseParams = {
78634 'SERVICE': 'WMS',
78635 'VERSION': ol.DEFAULT_WMS_VERSION,
78636 'REQUEST': 'GetFeatureInfo',
78637 'FORMAT': 'image/png',
78638 'TRANSPARENT': true,
78639 'QUERY_LAYERS': this.params_['LAYERS']
78640 };
78641 ol.obj.assign(baseParams, this.params_, params);
78642
78643 var x = Math.floor((coordinate[0] - tileExtent[0]) / tileResolution);
78644 var y = Math.floor((tileExtent[3] - coordinate[1]) / tileResolution);
78645
78646 baseParams[this.v13_ ? 'I' : 'X'] = x;
78647 baseParams[this.v13_ ? 'J' : 'Y'] = y;
78648
78649 return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
78650 1, projectionObj, baseParams);
78651};
78652
78653
78654/**
78655 * @inheritDoc
78656 */
78657ol.source.TileWMS.prototype.getGutterInternal = function() {
78658 return this.gutter_;
78659};
78660
78661
78662/**
78663 * @inheritDoc
78664 */
78665ol.source.TileWMS.prototype.getKeyZXY = function(z, x, y) {
78666 return this.coordKeyPrefix_ + ol.source.TileImage.prototype.getKeyZXY.call(this, z, x, y);
78667};
78668
78669
78670/**
78671 * Get the user-provided params, i.e. those passed to the constructor through
78672 * the "params" option, and possibly updated using the updateParams method.
78673 * @return {Object} Params.
78674 * @api
78675 */
78676ol.source.TileWMS.prototype.getParams = function() {
78677 return this.params_;
78678};
78679
78680
78681/**
78682 * @param {ol.TileCoord} tileCoord Tile coordinate.
78683 * @param {ol.Size} tileSize Tile size.
78684 * @param {ol.Extent} tileExtent Tile extent.
78685 * @param {number} pixelRatio Pixel ratio.
78686 * @param {ol.proj.Projection} projection Projection.
78687 * @param {Object} params Params.
78688 * @return {string|undefined} Request URL.
78689 * @private
78690 */
78691ol.source.TileWMS.prototype.getRequestUrl_ = function(tileCoord, tileSize, tileExtent,
78692 pixelRatio, projection, params) {
78693
78694 var urls = this.urls;
78695 if (!urls) {
78696 return undefined;
78697 }
78698
78699 params['WIDTH'] = tileSize[0];
78700 params['HEIGHT'] = tileSize[1];
78701
78702 params[this.v13_ ? 'CRS' : 'SRS'] = projection.getCode();
78703
78704 if (!('STYLES' in this.params_)) {
78705 params['STYLES'] = '';
78706 }
78707
78708 if (pixelRatio != 1) {
78709 switch (this.serverType_) {
78710 case ol.source.WMSServerType.GEOSERVER:
78711 var dpi = (90 * pixelRatio + 0.5) | 0;
78712 if ('FORMAT_OPTIONS' in params) {
78713 params['FORMAT_OPTIONS'] += ';dpi:' + dpi;
78714 } else {
78715 params['FORMAT_OPTIONS'] = 'dpi:' + dpi;
78716 }
78717 break;
78718 case ol.source.WMSServerType.MAPSERVER:
78719 params['MAP_RESOLUTION'] = 90 * pixelRatio;
78720 break;
78721 case ol.source.WMSServerType.CARMENTA_SERVER:
78722 case ol.source.WMSServerType.QGIS:
78723 params['DPI'] = 90 * pixelRatio;
78724 break;
78725 default:
78726 ol.asserts.assert(false, 52); // Unknown `serverType` configured
78727 break;
78728 }
78729 }
78730
78731 var axisOrientation = projection.getAxisOrientation();
78732 var bbox = tileExtent;
78733 if (this.v13_ && axisOrientation.substr(0, 2) == 'ne') {
78734 var tmp;
78735 tmp = tileExtent[0];
78736 bbox[0] = tileExtent[1];
78737 bbox[1] = tmp;
78738 tmp = tileExtent[2];
78739 bbox[2] = tileExtent[3];
78740 bbox[3] = tmp;
78741 }
78742 params['BBOX'] = bbox.join(',');
78743
78744 var url;
78745 if (urls.length == 1) {
78746 url = urls[0];
78747 } else {
78748 var index = ol.math.modulo(ol.tilecoord.hash(tileCoord), urls.length);
78749 url = urls[index];
78750 }
78751 return ol.uri.appendParams(url, params);
78752};
78753
78754
78755/**
78756 * @inheritDoc
78757 */
78758ol.source.TileWMS.prototype.getTilePixelRatio = function(pixelRatio) {
78759 return (!this.hidpi_ || this.serverType_ === undefined) ? 1 :
78760 /** @type {number} */ (pixelRatio);
78761};
78762
78763
78764/**
78765 * @private
78766 */
78767ol.source.TileWMS.prototype.resetCoordKeyPrefix_ = function() {
78768 var i = 0;
78769 var res = [];
78770
78771 if (this.urls) {
78772 var j, jj;
78773 for (j = 0, jj = this.urls.length; j < jj; ++j) {
78774 res[i++] = this.urls[j];
78775 }
78776 }
78777
78778 this.coordKeyPrefix_ = res.join('#');
78779};
78780
78781
78782/**
78783 * @private
78784 * @return {string} The key for the current params.
78785 */
78786ol.source.TileWMS.prototype.getKeyForParams_ = function() {
78787 var i = 0;
78788 var res = [];
78789 for (var key in this.params_) {
78790 res[i++] = key + '-' + this.params_[key];
78791 }
78792 return res.join('/');
78793};
78794
78795
78796/**
78797 * @inheritDoc
78798 */
78799ol.source.TileWMS.prototype.fixedTileUrlFunction = function(tileCoord, pixelRatio, projection) {
78800
78801 var tileGrid = this.getTileGrid();
78802 if (!tileGrid) {
78803 tileGrid = this.getTileGridForProjection(projection);
78804 }
78805
78806 if (tileGrid.getResolutions().length <= tileCoord[0]) {
78807 return undefined;
78808 }
78809
78810 if (pixelRatio != 1 && (!this.hidpi_ || this.serverType_ === undefined)) {
78811 pixelRatio = 1;
78812 }
78813
78814 var tileResolution = tileGrid.getResolution(tileCoord[0]);
78815 var tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tmpExtent_);
78816 var tileSize = ol.size.toSize(
78817 tileGrid.getTileSize(tileCoord[0]), this.tmpSize);
78818
78819 var gutter = this.gutter_;
78820 if (gutter !== 0) {
78821 tileSize = ol.size.buffer(tileSize, gutter, this.tmpSize);
78822 tileExtent = ol.extent.buffer(tileExtent,
78823 tileResolution * gutter, tileExtent);
78824 }
78825
78826 if (pixelRatio != 1) {
78827 tileSize = ol.size.scale(tileSize, pixelRatio, this.tmpSize);
78828 }
78829
78830 var baseParams = {
78831 'SERVICE': 'WMS',
78832 'VERSION': ol.DEFAULT_WMS_VERSION,
78833 'REQUEST': 'GetMap',
78834 'FORMAT': 'image/png',
78835 'TRANSPARENT': true
78836 };
78837 ol.obj.assign(baseParams, this.params_);
78838
78839 return this.getRequestUrl_(tileCoord, tileSize, tileExtent,
78840 pixelRatio, projection, baseParams);
78841};
78842
78843/**
78844 * @inheritDoc
78845 */
78846ol.source.TileWMS.prototype.setUrls = function(urls) {
78847 ol.source.TileImage.prototype.setUrls.call(this, urls);
78848 this.resetCoordKeyPrefix_();
78849};
78850
78851
78852/**
78853 * Update the user-provided params.
78854 * @param {Object} params Params.
78855 * @api
78856 */
78857ol.source.TileWMS.prototype.updateParams = function(params) {
78858 ol.obj.assign(this.params_, params);
78859 this.resetCoordKeyPrefix_();
78860 this.updateV13_();
78861 this.setKey(this.getKeyForParams_());
78862};
78863
78864
78865/**
78866 * @private
78867 */
78868ol.source.TileWMS.prototype.updateV13_ = function() {
78869 var version = this.params_['VERSION'] || ol.DEFAULT_WMS_VERSION;
78870 this.v13_ = ol.string.compareVersions(version, '1.3') >= 0;
78871};
78872
78873goog.provide('ol.VectorImageTile');
78874
78875goog.require('ol');
78876goog.require('ol.Tile');
78877goog.require('ol.TileState');
78878goog.require('ol.array');
78879goog.require('ol.dom');
78880goog.require('ol.events');
78881goog.require('ol.extent');
78882goog.require('ol.events.EventType');
78883goog.require('ol.featureloader');
78884
78885
78886/**
78887 * @constructor
78888 * @extends {ol.Tile}
78889 * @param {ol.TileCoord} tileCoord Tile coordinate.
78890 * @param {ol.TileState} state State.
78891 * @param {string} src Data source url.
78892 * @param {ol.format.Feature} format Feature format.
78893 * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
78894 * @param {ol.TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
78895 * @param {ol.TileUrlFunctionType} tileUrlFunction Tile url function.
78896 * @param {ol.tilegrid.TileGrid} sourceTileGrid Tile grid of the source.
78897 * @param {ol.tilegrid.TileGrid} tileGrid Tile grid of the renderer.
78898 * @param {Object.<string,ol.VectorTile>} sourceTiles Source tiles.
78899 * @param {number} pixelRatio Pixel ratio.
78900 * @param {ol.proj.Projection} projection Projection.
78901 * @param {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string,
78902 * ol.format.Feature, ol.TileLoadFunctionType)} tileClass Class to
78903 * instantiate for source tiles.
78904 * @param {function(this: ol.source.VectorTile, ol.events.Event)} handleTileChange
78905 * Function to call when a source tile's state changes.
78906 */
78907ol.VectorImageTile = function(tileCoord, state, src, format, tileLoadFunction,
78908 urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles,
78909 pixelRatio, projection, tileClass, handleTileChange) {
78910
78911 ol.Tile.call(this, tileCoord, state);
78912
78913 /**
78914 * @private
78915 * @type {Object.<string, CanvasRenderingContext2D>}
78916 */
78917 this.context_ = {};
78918
78919 /**
78920 * @private
78921 * @type {ol.FeatureLoader}
78922 */
78923 this.loader_;
78924
78925 /**
78926 * @private
78927 * @type {Object.<string, ol.TileReplayState>}
78928 */
78929 this.replayState_ = {};
78930
78931 /**
78932 * @private
78933 * @type {Object.<string,ol.VectorTile>}
78934 */
78935 this.sourceTiles_ = sourceTiles;
78936
78937 /**
78938 * Keys of source tiles used by this tile. Use with {@link #getTile}.
78939 * @type {Array.<string>}
78940 */
78941 this.tileKeys = [];
78942
78943 /**
78944 * @type {string}
78945 */
78946 this.src_ = src;
78947
78948 /**
78949 * @type {ol.TileCoord}
78950 */
78951 this.wrappedTileCoord = urlTileCoord;
78952
78953 /**
78954 * @type {Array.<ol.EventsKey>}
78955 */
78956 this.loadListenerKeys_ = [];
78957
78958 /**
78959 * @type {Array.<ol.EventsKey>}
78960 */
78961 this.sourceTileListenerKeys_ = [];
78962
78963 if (urlTileCoord) {
78964 var extent = tileGrid.getTileCoordExtent(urlTileCoord);
78965 var resolution = tileGrid.getResolution(tileCoord[0]);
78966 var sourceZ = sourceTileGrid.getZForResolution(resolution);
78967 sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) {
78968 var sharedExtent = ol.extent.getIntersection(extent,
78969 sourceTileGrid.getTileCoordExtent(sourceTileCoord));
78970 if (ol.extent.getWidth(sharedExtent) / resolution >= 0.5 &&
78971 ol.extent.getHeight(sharedExtent) / resolution >= 0.5) {
78972 // only include source tile if overlap is at least 1 pixel
78973 var sourceTileKey = sourceTileCoord.toString();
78974 var sourceTile = sourceTiles[sourceTileKey];
78975 if (!sourceTile) {
78976 var tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection);
78977 sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord,
78978 tileUrl == undefined ? ol.TileState.EMPTY : ol.TileState.IDLE,
78979 tileUrl == undefined ? '' : tileUrl,
78980 format, tileLoadFunction);
78981 this.sourceTileListenerKeys_.push(
78982 ol.events.listen(sourceTile, ol.events.EventType.CHANGE, handleTileChange));
78983 }
78984 sourceTile.consumers++;
78985 this.tileKeys.push(sourceTileKey);
78986 }
78987 }.bind(this));
78988 }
78989
78990};
78991ol.inherits(ol.VectorImageTile, ol.Tile);
78992
78993
78994/**
78995 * @inheritDoc
78996 */
78997ol.VectorImageTile.prototype.disposeInternal = function() {
78998 for (var i = 0, ii = this.tileKeys.length; i < ii; ++i) {
78999 var sourceTileKey = this.tileKeys[i];
79000 var sourceTile = this.getTile(sourceTileKey);
79001 sourceTile.consumers--;
79002 if (sourceTile.consumers == 0) {
79003 delete this.sourceTiles_[sourceTileKey];
79004 sourceTile.dispose();
79005 }
79006 }
79007 this.tileKeys.length = 0;
79008 this.sourceTiles_ = null;
79009 if (this.state == ol.TileState.LOADING) {
79010 this.loadListenerKeys_.forEach(ol.events.unlistenByKey);
79011 this.loadListenerKeys_.length = 0;
79012 }
79013 if (this.interimTile) {
79014 this.interimTile.dispose();
79015 }
79016 this.state = ol.TileState.ABORT;
79017 this.changed();
79018 this.sourceTileListenerKeys_.forEach(ol.events.unlistenByKey);
79019 this.sourceTileListenerKeys_.length = 0;
79020 ol.Tile.prototype.disposeInternal.call(this);
79021};
79022
79023
79024/**
79025 * @param {ol.layer.Layer} layer Layer.
79026 * @return {CanvasRenderingContext2D} The rendering context.
79027 */
79028ol.VectorImageTile.prototype.getContext = function(layer) {
79029 var key = ol.getUid(layer).toString();
79030 if (!(key in this.context_)) {
79031 this.context_[key] = ol.dom.createCanvasContext2D();
79032 }
79033 return this.context_[key];
79034};
79035
79036
79037/**
79038 * Get the Canvas for this tile.
79039 * @param {ol.layer.Layer} layer Layer.
79040 * @return {HTMLCanvasElement} Canvas.
79041 */
79042ol.VectorImageTile.prototype.getImage = function(layer) {
79043 return this.getReplayState(layer).renderedTileRevision == -1 ?
79044 null : this.getContext(layer).canvas;
79045};
79046
79047
79048/**
79049 * @param {ol.layer.Layer} layer Layer.
79050 * @return {ol.TileReplayState} The replay state.
79051 */
79052ol.VectorImageTile.prototype.getReplayState = function(layer) {
79053 var key = ol.getUid(layer).toString();
79054 if (!(key in this.replayState_)) {
79055 this.replayState_[key] = {
79056 dirty: false,
79057 renderedRenderOrder: null,
79058 renderedRevision: -1,
79059 renderedTileRevision: -1
79060 };
79061 }
79062 return this.replayState_[key];
79063};
79064
79065
79066/**
79067 * @inheritDoc
79068 */
79069ol.VectorImageTile.prototype.getKey = function() {
79070 return this.tileKeys.join('/') + '/' + this.src_;
79071};
79072
79073
79074/**
79075 * @param {string} tileKey Key (tileCoord) of the source tile.
79076 * @return {ol.VectorTile} Source tile.
79077 */
79078ol.VectorImageTile.prototype.getTile = function(tileKey) {
79079 return this.sourceTiles_[tileKey];
79080};
79081
79082
79083/**
79084 * @inheritDoc
79085 */
79086ol.VectorImageTile.prototype.load = function() {
79087 var leftToLoad = 0;
79088 if (this.state == ol.TileState.IDLE) {
79089 this.setState(ol.TileState.LOADING);
79090 }
79091 if (this.state == ol.TileState.LOADING) {
79092 this.tileKeys.forEach(function(sourceTileKey) {
79093 var sourceTile = this.getTile(sourceTileKey);
79094 if (sourceTile.state == ol.TileState.IDLE) {
79095 sourceTile.setLoader(this.loader_);
79096 sourceTile.load();
79097 }
79098 if (sourceTile.state == ol.TileState.LOADING) {
79099 var key = ol.events.listen(sourceTile, ol.events.EventType.CHANGE, function(e) {
79100 var state = sourceTile.getState();
79101 if (state == ol.TileState.LOADED ||
79102 state == ol.TileState.ERROR) {
79103 --leftToLoad;
79104 ol.events.unlistenByKey(key);
79105 ol.array.remove(this.loadListenerKeys_, key);
79106 if (leftToLoad == 0) {
79107 this.finishLoading_();
79108 }
79109 }
79110 }.bind(this));
79111 this.loadListenerKeys_.push(key);
79112 ++leftToLoad;
79113 }
79114 }.bind(this));
79115 }
79116 if (leftToLoad == 0) {
79117 setTimeout(this.finishLoading_.bind(this), 0);
79118 }
79119};
79120
79121
79122/**
79123 * @private
79124 */
79125ol.VectorImageTile.prototype.finishLoading_ = function() {
79126 var errors = false;
79127 var loaded = this.tileKeys.length;
79128 var state;
79129 for (var i = loaded - 1; i >= 0; --i) {
79130 state = this.getTile(this.tileKeys[i]).getState();
79131 if (state != ol.TileState.LOADED) {
79132 if (state == ol.TileState.ERROR) {
79133 errors = true;
79134 }
79135 --loaded;
79136 }
79137 }
79138 this.setState(loaded > 0 ?
79139 ol.TileState.LOADED :
79140 (errors ? ol.TileState.ERROR : ol.TileState.EMPTY));
79141};
79142
79143
79144/**
79145 * Sets the loader for a tile.
79146 * @param {ol.VectorTile} tile Vector tile.
79147 * @param {string} url URL.
79148 */
79149ol.VectorImageTile.defaultLoadFunction = function(tile, url) {
79150 var loader = ol.featureloader.loadFeaturesXhr(
79151 url, tile.getFormat(), tile.onLoad.bind(tile), tile.onError.bind(tile));
79152
79153 tile.setLoader(loader);
79154};
79155
79156goog.provide('ol.VectorTile');
79157
79158goog.require('ol');
79159goog.require('ol.Tile');
79160goog.require('ol.TileState');
79161
79162
79163/**
79164 * @constructor
79165 * @extends {ol.Tile}
79166 * @param {ol.TileCoord} tileCoord Tile coordinate.
79167 * @param {ol.TileState} state State.
79168 * @param {string} src Data source url.
79169 * @param {ol.format.Feature} format Feature format.
79170 * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
79171 */
79172ol.VectorTile = function(tileCoord, state, src, format, tileLoadFunction) {
79173
79174 ol.Tile.call(this, tileCoord, state);
79175
79176 /**
79177 * @type {number}
79178 */
79179 this.consumers = 0;
79180
79181 /**
79182 * @private
79183 * @type {ol.Extent}
79184 */
79185 this.extent_ = null;
79186
79187 /**
79188 * @private
79189 * @type {ol.format.Feature}
79190 */
79191 this.format_ = format;
79192
79193 /**
79194 * @private
79195 * @type {Array.<ol.Feature>}
79196 */
79197 this.features_ = null;
79198
79199 /**
79200 * @private
79201 * @type {ol.FeatureLoader}
79202 */
79203 this.loader_;
79204
79205 /**
79206 * Data projection
79207 * @private
79208 * @type {ol.proj.Projection}
79209 */
79210 this.projection_;
79211
79212 /**
79213 * @private
79214 * @type {Object.<string, ol.render.ReplayGroup>}
79215 */
79216 this.replayGroups_ = {};
79217
79218 /**
79219 * @private
79220 * @type {ol.TileLoadFunctionType}
79221 */
79222 this.tileLoadFunction_ = tileLoadFunction;
79223
79224 /**
79225 * @private
79226 * @type {string}
79227 */
79228 this.url_ = src;
79229
79230};
79231ol.inherits(ol.VectorTile, ol.Tile);
79232
79233
79234/**
79235 * @inheritDoc
79236 */
79237ol.VectorTile.prototype.disposeInternal = function() {
79238 this.features_ = null;
79239 this.replayGroups_ = {};
79240 this.state = ol.TileState.ABORT;
79241 this.changed();
79242 ol.Tile.prototype.disposeInternal.call(this);
79243};
79244
79245
79246/**
79247 * Gets the extent of the vector tile.
79248 * @return {ol.Extent} The extent.
79249 */
79250ol.VectorTile.prototype.getExtent = function() {
79251 return this.extent_ || ol.VectorTile.DEFAULT_EXTENT;
79252};
79253
79254
79255/**
79256 * Get the feature format assigned for reading this tile's features.
79257 * @return {ol.format.Feature} Feature format.
79258 * @api
79259 */
79260ol.VectorTile.prototype.getFormat = function() {
79261 return this.format_;
79262};
79263
79264
79265/**
79266 * Get the features for this tile. Geometries will be in the projection returned
79267 * by {@link ol.VectorTile#getProjection}.
79268 * @return {Array.<ol.Feature|ol.render.Feature>} Features.
79269 * @api
79270 */
79271ol.VectorTile.prototype.getFeatures = function() {
79272 return this.features_;
79273};
79274
79275
79276/**
79277 * @inheritDoc
79278 */
79279ol.VectorTile.prototype.getKey = function() {
79280 return this.url_;
79281};
79282
79283
79284/**
79285 * Get the feature projection of features returned by
79286 * {@link ol.VectorTile#getFeatures}.
79287 * @return {ol.proj.Projection} Feature projection.
79288 * @api
79289 */
79290ol.VectorTile.prototype.getProjection = function() {
79291 return this.projection_;
79292};
79293
79294
79295/**
79296 * @param {ol.layer.Layer} layer Layer.
79297 * @param {string} key Key.
79298 * @return {ol.render.ReplayGroup} Replay group.
79299 */
79300ol.VectorTile.prototype.getReplayGroup = function(layer, key) {
79301 return this.replayGroups_[ol.getUid(layer) + ',' + key];
79302};
79303
79304
79305/**
79306 * @inheritDoc
79307 */
79308ol.VectorTile.prototype.load = function() {
79309 if (this.state == ol.TileState.IDLE) {
79310 this.setState(ol.TileState.LOADING);
79311 this.tileLoadFunction_(this, this.url_);
79312 this.loader_(null, NaN, null);
79313 }
79314};
79315
79316
79317/**
79318 * Handler for successful tile load.
79319 * @param {Array.<ol.Feature>} features The loaded features.
79320 * @param {ol.proj.Projection} dataProjection Data projection.
79321 * @param {ol.Extent} extent Extent.
79322 */
79323ol.VectorTile.prototype.onLoad = function(features, dataProjection, extent) {
79324 this.setProjection(dataProjection);
79325 this.setFeatures(features);
79326 this.setExtent(extent);
79327};
79328
79329
79330/**
79331 * Handler for tile load errors.
79332 */
79333ol.VectorTile.prototype.onError = function() {
79334 this.setState(ol.TileState.ERROR);
79335};
79336
79337
79338/**
79339 * Function for use in an {@link ol.source.VectorTile}'s `tileLoadFunction`.
79340 * Sets the extent of the vector tile. This is only required for tiles in
79341 * projections with `tile-pixels` as units. The extent should be set to
79342 * `[0, 0, tilePixelSize, tilePixelSize]`, where `tilePixelSize` is calculated
79343 * by multiplying the tile size with the tile pixel ratio. For sources using
79344 * {@link ol.format.MVT} as feature format, the
79345 * {@link ol.format.MVT#getLastExtent} method will return the correct extent.
79346 * The default is `[0, 0, 4096, 4096]`.
79347 * @param {ol.Extent} extent The extent.
79348 * @api
79349 */
79350ol.VectorTile.prototype.setExtent = function(extent) {
79351 this.extent_ = extent;
79352};
79353
79354
79355/**
79356 * Function for use in an {@link ol.source.VectorTile}'s `tileLoadFunction`.
79357 * Sets the features for the tile.
79358 * @param {Array.<ol.Feature>} features Features.
79359 * @api
79360 */
79361ol.VectorTile.prototype.setFeatures = function(features) {
79362 this.features_ = features;
79363 this.setState(ol.TileState.LOADED);
79364};
79365
79366
79367/**
79368 * Function for use in an {@link ol.source.VectorTile}'s `tileLoadFunction`.
79369 * Sets the projection of the features that were added with
79370 * {@link ol.VectorTile#setFeatures}.
79371 * @param {ol.proj.Projection} projection Feature projection.
79372 * @api
79373 */
79374ol.VectorTile.prototype.setProjection = function(projection) {
79375 this.projection_ = projection;
79376};
79377
79378
79379/**
79380 * @param {ol.layer.Layer} layer Layer.
79381 * @param {string} key Key.
79382 * @param {ol.render.ReplayGroup} replayGroup Replay group.
79383 */
79384ol.VectorTile.prototype.setReplayGroup = function(layer, key, replayGroup) {
79385 this.replayGroups_[ol.getUid(layer) + ',' + key] = replayGroup;
79386};
79387
79388
79389/**
79390 * Set the feature loader for reading this tile's features.
79391 * @param {ol.FeatureLoader} loader Feature loader.
79392 * @api
79393 */
79394ol.VectorTile.prototype.setLoader = function(loader) {
79395 this.loader_ = loader;
79396};
79397
79398
79399/**
79400 * @const
79401 * @type {ol.Extent}
79402 */
79403ol.VectorTile.DEFAULT_EXTENT = [0, 0, 4096, 4096];
79404
79405goog.provide('ol.source.VectorTile');
79406
79407goog.require('ol');
79408goog.require('ol.TileState');
79409goog.require('ol.VectorImageTile');
79410goog.require('ol.VectorTile');
79411goog.require('ol.proj');
79412goog.require('ol.size');
79413goog.require('ol.tilegrid');
79414goog.require('ol.source.UrlTile');
79415
79416
79417/**
79418 * @classdesc
79419 * Class for layer sources providing vector data divided into a tile grid, to be
79420 * used with {@link ol.layer.VectorTile}. Although this source receives tiles
79421 * with vector features from the server, it is not meant for feature editing.
79422 * Features are optimized for rendering, their geometries are clipped at or near
79423 * tile boundaries and simplified for a view resolution. See
79424 * {@link ol.source.Vector} for vector sources that are suitable for feature
79425 * editing.
79426 *
79427 * @constructor
79428 * @fires ol.source.Tile.Event
79429 * @extends {ol.source.UrlTile}
79430 * @param {olx.source.VectorTileOptions} options Vector tile options.
79431 * @api
79432 */
79433ol.source.VectorTile = function(options) {
79434 var projection = options.projection || 'EPSG:3857';
79435
79436 var extent = options.extent || ol.tilegrid.extentFromProjection(projection);
79437
79438 var tileGrid = options.tileGrid || ol.tilegrid.createXYZ({
79439 extent: extent,
79440 maxZoom: options.maxZoom || 22,
79441 minZoom: options.minZoom,
79442 tileSize: options.tileSize || 512
79443 });
79444
79445 ol.source.UrlTile.call(this, {
79446 attributions: options.attributions,
79447 cacheSize: options.cacheSize !== undefined ? options.cacheSize : 128,
79448 extent: extent,
79449 logo: options.logo,
79450 opaque: false,
79451 projection: projection,
79452 state: options.state,
79453 tileGrid: tileGrid,
79454 tileLoadFunction: options.tileLoadFunction ?
79455 options.tileLoadFunction : ol.VectorImageTile.defaultLoadFunction,
79456 tileUrlFunction: options.tileUrlFunction,
79457 url: options.url,
79458 urls: options.urls,
79459 wrapX: options.wrapX === undefined ? true : options.wrapX
79460 });
79461
79462 /**
79463 * @private
79464 * @type {ol.format.Feature}
79465 */
79466 this.format_ = options.format ? options.format : null;
79467
79468 /**
79469 * @private
79470 * @type {Object.<string,ol.VectorTile>}
79471 */
79472 this.sourceTiles_ = {};
79473
79474 /**
79475 * @private
79476 * @type {boolean}
79477 */
79478 this.overlaps_ = options.overlaps == undefined ? true : options.overlaps;
79479
79480 /**
79481 * @protected
79482 * @type {function(new: ol.VectorTile, ol.TileCoord, ol.TileState, string,
79483 * ol.format.Feature, ol.TileLoadFunctionType)}
79484 */
79485 this.tileClass = options.tileClass ? options.tileClass : ol.VectorTile;
79486
79487 /**
79488 * @private
79489 * @type {Object.<string,ol.tilegrid.TileGrid>}
79490 */
79491 this.tileGrids_ = {};
79492
79493 if (!this.tileGrid) {
79494 this.tileGrid = this.getTileGridForProjection(ol.proj.get(options.projection || 'EPSG:3857'));
79495 }
79496
79497};
79498ol.inherits(ol.source.VectorTile, ol.source.UrlTile);
79499
79500
79501/**
79502 * @return {boolean} The source can have overlapping geometries.
79503 */
79504ol.source.VectorTile.prototype.getOverlaps = function() {
79505 return this.overlaps_;
79506};
79507
79508
79509/**
79510 * @inheritDoc
79511 */
79512ol.source.VectorTile.prototype.getTile = function(z, x, y, pixelRatio, projection) {
79513 var tileCoordKey = this.getKeyZXY(z, x, y);
79514 if (this.tileCache.containsKey(tileCoordKey)) {
79515 return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
79516 } else {
79517 var tileCoord = [z, x, y];
79518 var urlTileCoord = this.getTileCoordForTileUrlFunction(
79519 tileCoord, projection);
79520 var tileUrl = urlTileCoord ?
79521 this.tileUrlFunction(urlTileCoord, pixelRatio, projection) : undefined;
79522 var tile = new ol.VectorImageTile(
79523 tileCoord,
79524 tileUrl !== undefined ? ol.TileState.IDLE : ol.TileState.EMPTY,
79525 tileUrl !== undefined ? tileUrl : '',
79526 this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction,
79527 this.tileGrid, this.getTileGridForProjection(projection),
79528 this.sourceTiles_, pixelRatio, projection, this.tileClass,
79529 this.handleTileChange.bind(this));
79530
79531 this.tileCache.set(tileCoordKey, tile);
79532 return tile;
79533 }
79534};
79535
79536
79537/**
79538 * @inheritDoc
79539 */
79540ol.source.VectorTile.prototype.getTileGridForProjection = function(projection) {
79541 var code = projection.getCode();
79542 var tileGrid = this.tileGrids_[code];
79543 if (!tileGrid) {
79544 // A tile grid that matches the tile size of the source tile grid is more
79545 // likely to have 1:1 relationships between source tiles and rendered tiles.
79546 var sourceTileGrid = this.tileGrid;
79547 tileGrid = this.tileGrids_[code] = ol.tilegrid.createForProjection(projection, undefined,
79548 sourceTileGrid ? sourceTileGrid.getTileSize(sourceTileGrid.getMinZoom()) : undefined);
79549 }
79550 return tileGrid;
79551};
79552
79553
79554/**
79555 * @inheritDoc
79556 */
79557ol.source.VectorTile.prototype.getTilePixelRatio = function(pixelRatio) {
79558 return pixelRatio;
79559};
79560
79561
79562/**
79563 * @inheritDoc
79564 */
79565ol.source.VectorTile.prototype.getTilePixelSize = function(z, pixelRatio, projection) {
79566 var tileSize = ol.size.toSize(this.getTileGridForProjection(projection).getTileSize(z));
79567 return [Math.round(tileSize[0] * pixelRatio), Math.round(tileSize[1] * pixelRatio)];
79568};
79569
79570goog.provide('ol.source.WMTSRequestEncoding');
79571
79572/**
79573 * Request encoding. One of 'KVP', 'REST'.
79574 * @enum {string}
79575 */
79576ol.source.WMTSRequestEncoding = {
79577 KVP: 'KVP', // see spec §8
79578 REST: 'REST' // see spec §10
79579};
79580
79581goog.provide('ol.tilegrid.WMTS');
79582
79583goog.require('ol');
79584goog.require('ol.array');
79585goog.require('ol.proj');
79586goog.require('ol.tilegrid.TileGrid');
79587
79588
79589/**
79590 * @classdesc
79591 * Set the grid pattern for sources accessing WMTS tiled-image servers.
79592 *
79593 * @constructor
79594 * @extends {ol.tilegrid.TileGrid}
79595 * @param {olx.tilegrid.WMTSOptions} options WMTS options.
79596 * @struct
79597 * @api
79598 */
79599ol.tilegrid.WMTS = function(options) {
79600 /**
79601 * @private
79602 * @type {!Array.<string>}
79603 */
79604 this.matrixIds_ = options.matrixIds;
79605 // FIXME: should the matrixIds become optional?
79606
79607 ol.tilegrid.TileGrid.call(this, {
79608 extent: options.extent,
79609 origin: options.origin,
79610 origins: options.origins,
79611 resolutions: options.resolutions,
79612 tileSize: options.tileSize,
79613 tileSizes: options.tileSizes,
79614 sizes: options.sizes
79615 });
79616};
79617ol.inherits(ol.tilegrid.WMTS, ol.tilegrid.TileGrid);
79618
79619
79620/**
79621 * @param {number} z Z.
79622 * @return {string} MatrixId..
79623 */
79624ol.tilegrid.WMTS.prototype.getMatrixId = function(z) {
79625 return this.matrixIds_[z];
79626};
79627
79628
79629/**
79630 * Get the list of matrix identifiers.
79631 * @return {Array.<string>} MatrixIds.
79632 * @api
79633 */
79634ol.tilegrid.WMTS.prototype.getMatrixIds = function() {
79635 return this.matrixIds_;
79636};
79637
79638
79639/**
79640 * Create a tile grid from a WMTS capabilities matrix set and an
79641 * optional TileMatrixSetLimits.
79642 * @param {Object} matrixSet An object representing a matrixSet in the
79643 * capabilities document.
79644 * @param {ol.Extent=} opt_extent An optional extent to restrict the tile
79645 * ranges the server provides.
79646 * @param {Array.<Object>=} opt_matrixLimits An optional object representing
79647 * the available matrices for tileGrid.
79648 * @return {ol.tilegrid.WMTS} WMTS tileGrid instance.
79649 * @api
79650 */
79651ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet = function(matrixSet, opt_extent,
79652 opt_matrixLimits) {
79653
79654 /** @type {!Array.<number>} */
79655 var resolutions = [];
79656 /** @type {!Array.<string>} */
79657 var matrixIds = [];
79658 /** @type {!Array.<ol.Coordinate>} */
79659 var origins = [];
79660 /** @type {!Array.<ol.Size>} */
79661 var tileSizes = [];
79662 /** @type {!Array.<ol.Size>} */
79663 var sizes = [];
79664
79665 var matrixLimits = opt_matrixLimits !== undefined ? opt_matrixLimits : [];
79666
79667 var supportedCRSPropName = 'SupportedCRS';
79668 var matrixIdsPropName = 'TileMatrix';
79669 var identifierPropName = 'Identifier';
79670 var scaleDenominatorPropName = 'ScaleDenominator';
79671 var topLeftCornerPropName = 'TopLeftCorner';
79672 var tileWidthPropName = 'TileWidth';
79673 var tileHeightPropName = 'TileHeight';
79674
79675 var projection;
79676 projection = ol.proj.get(matrixSet[supportedCRSPropName].replace(
79677 /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
79678 var metersPerUnit = projection.getMetersPerUnit();
79679 // swap origin x and y coordinates if axis orientation is lat/long
79680 var switchOriginXY = projection.getAxisOrientation().substr(0, 2) == 'ne';
79681
79682 matrixSet[matrixIdsPropName].sort(function(a, b) {
79683 return b[scaleDenominatorPropName] - a[scaleDenominatorPropName];
79684 });
79685
79686 matrixSet[matrixIdsPropName].forEach(function(elt, index, array) {
79687
79688 var matrixAvailable;
79689 // use of matrixLimits to filter TileMatrices from GetCapabilities
79690 // TileMatrixSet from unavailable matrix levels.
79691 if (matrixLimits.length > 0) {
79692 matrixAvailable = ol.array.find(matrixLimits,
79693 function(elt_ml, index_ml, array_ml) {
79694 return elt[identifierPropName] == elt_ml[matrixIdsPropName];
79695 });
79696 } else {
79697 matrixAvailable = true;
79698 }
79699
79700 if (matrixAvailable) {
79701 matrixIds.push(elt[identifierPropName]);
79702 var resolution = elt[scaleDenominatorPropName] * 0.28E-3 / metersPerUnit;
79703 var tileWidth = elt[tileWidthPropName];
79704 var tileHeight = elt[tileHeightPropName];
79705 if (switchOriginXY) {
79706 origins.push([elt[topLeftCornerPropName][1],
79707 elt[topLeftCornerPropName][0]]);
79708 } else {
79709 origins.push(elt[topLeftCornerPropName]);
79710 }
79711 resolutions.push(resolution);
79712 tileSizes.push(tileWidth == tileHeight ?
79713 tileWidth : [tileWidth, tileHeight]);
79714 // top-left origin, so height is negative
79715 sizes.push([elt['MatrixWidth'], -elt['MatrixHeight']]);
79716 }
79717 });
79718
79719 return new ol.tilegrid.WMTS({
79720 extent: opt_extent,
79721 origins: origins,
79722 resolutions: resolutions,
79723 matrixIds: matrixIds,
79724 tileSizes: tileSizes,
79725 sizes: sizes
79726 });
79727};
79728
79729goog.provide('ol.source.WMTS');
79730
79731goog.require('ol');
79732goog.require('ol.TileUrlFunction');
79733goog.require('ol.array');
79734goog.require('ol.extent');
79735goog.require('ol.obj');
79736goog.require('ol.proj');
79737goog.require('ol.source.TileImage');
79738goog.require('ol.source.WMTSRequestEncoding');
79739goog.require('ol.tilegrid.WMTS');
79740goog.require('ol.uri');
79741
79742
79743/**
79744 * @classdesc
79745 * Layer source for tile data from WMTS servers.
79746 *
79747 * @constructor
79748 * @extends {ol.source.TileImage}
79749 * @param {olx.source.WMTSOptions} options WMTS options.
79750 * @api
79751 */
79752ol.source.WMTS = function(options) {
79753
79754 // TODO: add support for TileMatrixLimits
79755
79756 /**
79757 * @private
79758 * @type {string}
79759 */
79760 this.version_ = options.version !== undefined ? options.version : '1.0.0';
79761
79762 /**
79763 * @private
79764 * @type {string}
79765 */
79766 this.format_ = options.format !== undefined ? options.format : 'image/jpeg';
79767
79768 /**
79769 * @private
79770 * @type {!Object}
79771 */
79772 this.dimensions_ = options.dimensions !== undefined ? options.dimensions : {};
79773
79774 /**
79775 * @private
79776 * @type {string}
79777 */
79778 this.layer_ = options.layer;
79779
79780 /**
79781 * @private
79782 * @type {string}
79783 */
79784 this.matrixSet_ = options.matrixSet;
79785
79786 /**
79787 * @private
79788 * @type {string}
79789 */
79790 this.style_ = options.style;
79791
79792 var urls = options.urls;
79793 if (urls === undefined && options.url !== undefined) {
79794 urls = ol.TileUrlFunction.expandUrl(options.url);
79795 }
79796
79797 // FIXME: should we guess this requestEncoding from options.url(s)
79798 // structure? that would mean KVP only if a template is not provided.
79799
79800 /**
79801 * @private
79802 * @type {ol.source.WMTSRequestEncoding}
79803 */
79804 this.requestEncoding_ = options.requestEncoding !== undefined ?
79805 /** @type {ol.source.WMTSRequestEncoding} */ (options.requestEncoding) :
79806 ol.source.WMTSRequestEncoding.KVP;
79807
79808 var requestEncoding = this.requestEncoding_;
79809
79810 // FIXME: should we create a default tileGrid?
79811 // we could issue a getCapabilities xhr to retrieve missing configuration
79812 var tileGrid = options.tileGrid;
79813
79814 // context property names are lower case to allow for a case insensitive
79815 // replacement as some services use different naming conventions
79816 var context = {
79817 'layer': this.layer_,
79818 'style': this.style_,
79819 'tilematrixset': this.matrixSet_
79820 };
79821
79822 if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
79823 ol.obj.assign(context, {
79824 'Service': 'WMTS',
79825 'Request': 'GetTile',
79826 'Version': this.version_,
79827 'Format': this.format_
79828 });
79829 }
79830
79831 var dimensions = this.dimensions_;
79832
79833 /**
79834 * @param {string} template Template.
79835 * @return {ol.TileUrlFunctionType} Tile URL function.
79836 */
79837 function createFromWMTSTemplate(template) {
79838
79839 // TODO: we may want to create our own appendParams function so that params
79840 // order conforms to wmts spec guidance, and so that we can avoid to escape
79841 // special template params
79842
79843 template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ?
79844 ol.uri.appendParams(template, context) :
79845 template.replace(/\{(\w+?)\}/g, function(m, p) {
79846 return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m;
79847 });
79848
79849 return (
79850 /**
79851 * @param {ol.TileCoord} tileCoord Tile coordinate.
79852 * @param {number} pixelRatio Pixel ratio.
79853 * @param {ol.proj.Projection} projection Projection.
79854 * @return {string|undefined} Tile URL.
79855 */
79856 function(tileCoord, pixelRatio, projection) {
79857 if (!tileCoord) {
79858 return undefined;
79859 } else {
79860 var localContext = {
79861 'TileMatrix': tileGrid.getMatrixId(tileCoord[0]),
79862 'TileCol': tileCoord[1],
79863 'TileRow': -tileCoord[2] - 1
79864 };
79865 ol.obj.assign(localContext, dimensions);
79866 var url = template;
79867 if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
79868 url = ol.uri.appendParams(url, localContext);
79869 } else {
79870 url = url.replace(/\{(\w+?)\}/g, function(m, p) {
79871 return localContext[p];
79872 });
79873 }
79874 return url;
79875 }
79876 });
79877 }
79878
79879 var tileUrlFunction = (urls && urls.length > 0) ?
79880 ol.TileUrlFunction.createFromTileUrlFunctions(
79881 urls.map(createFromWMTSTemplate)) :
79882 ol.TileUrlFunction.nullTileUrlFunction;
79883
79884 ol.source.TileImage.call(this, {
79885 attributions: options.attributions,
79886 cacheSize: options.cacheSize,
79887 crossOrigin: options.crossOrigin,
79888 logo: options.logo,
79889 projection: options.projection,
79890 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
79891 tileClass: options.tileClass,
79892 tileGrid: tileGrid,
79893 tileLoadFunction: options.tileLoadFunction,
79894 tilePixelRatio: options.tilePixelRatio,
79895 tileUrlFunction: tileUrlFunction,
79896 urls: urls,
79897 wrapX: options.wrapX !== undefined ? options.wrapX : false
79898 });
79899
79900 this.setKey(this.getKeyForDimensions_());
79901
79902};
79903ol.inherits(ol.source.WMTS, ol.source.TileImage);
79904
79905
79906/**
79907 * Get the dimensions, i.e. those passed to the constructor through the
79908 * "dimensions" option, and possibly updated using the updateDimensions
79909 * method.
79910 * @return {!Object} Dimensions.
79911 * @api
79912 */
79913ol.source.WMTS.prototype.getDimensions = function() {
79914 return this.dimensions_;
79915};
79916
79917
79918/**
79919 * Return the image format of the WMTS source.
79920 * @return {string} Format.
79921 * @api
79922 */
79923ol.source.WMTS.prototype.getFormat = function() {
79924 return this.format_;
79925};
79926
79927
79928/**
79929 * Return the layer of the WMTS source.
79930 * @return {string} Layer.
79931 * @api
79932 */
79933ol.source.WMTS.prototype.getLayer = function() {
79934 return this.layer_;
79935};
79936
79937
79938/**
79939 * Return the matrix set of the WMTS source.
79940 * @return {string} MatrixSet.
79941 * @api
79942 */
79943ol.source.WMTS.prototype.getMatrixSet = function() {
79944 return this.matrixSet_;
79945};
79946
79947
79948/**
79949 * Return the request encoding, either "KVP" or "REST".
79950 * @return {ol.source.WMTSRequestEncoding} Request encoding.
79951 * @api
79952 */
79953ol.source.WMTS.prototype.getRequestEncoding = function() {
79954 return this.requestEncoding_;
79955};
79956
79957
79958/**
79959 * Return the style of the WMTS source.
79960 * @return {string} Style.
79961 * @api
79962 */
79963ol.source.WMTS.prototype.getStyle = function() {
79964 return this.style_;
79965};
79966
79967
79968/**
79969 * Return the version of the WMTS source.
79970 * @return {string} Version.
79971 * @api
79972 */
79973ol.source.WMTS.prototype.getVersion = function() {
79974 return this.version_;
79975};
79976
79977
79978/**
79979 * @private
79980 * @return {string} The key for the current dimensions.
79981 */
79982ol.source.WMTS.prototype.getKeyForDimensions_ = function() {
79983 var i = 0;
79984 var res = [];
79985 for (var key in this.dimensions_) {
79986 res[i++] = key + '-' + this.dimensions_[key];
79987 }
79988 return res.join('/');
79989};
79990
79991
79992/**
79993 * Update the dimensions.
79994 * @param {Object} dimensions Dimensions.
79995 * @api
79996 */
79997ol.source.WMTS.prototype.updateDimensions = function(dimensions) {
79998 ol.obj.assign(this.dimensions_, dimensions);
79999 this.setKey(this.getKeyForDimensions_());
80000};
80001
80002
80003/**
80004 * Generate source options from a capabilities object.
80005 * @param {Object} wmtsCap An object representing the capabilities document.
80006 * @param {Object} config Configuration properties for the layer. Defaults for
80007 * the layer will apply if not provided.
80008 *
80009 * Required config properties:
80010 * - layer - {string} The layer identifier.
80011 *
80012 * Optional config properties:
80013 * - matrixSet - {string} The matrix set identifier, required if there is
80014 * more than one matrix set in the layer capabilities.
80015 * - projection - {string} The desired CRS when no matrixSet is specified.
80016 * eg: "EPSG:3857". If the desired projection is not available,
80017 * an error is thrown.
80018 * - requestEncoding - {string} url encoding format for the layer. Default is
80019 * the first tile url format found in the GetCapabilities response.
80020 * - style - {string} The name of the style
80021 * - format - {string} Image format for the layer. Default is the first
80022 * format returned in the GetCapabilities response.
80023 * - crossOrigin - {string|null|undefined} Cross origin. Default is `undefined`.
80024 * @return {?olx.source.WMTSOptions} WMTS source options object or `null` if the layer was not found.
80025 * @api
80026 */
80027ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
80028 var layers = wmtsCap['Contents']['Layer'];
80029 var l = ol.array.find(layers, function(elt, index, array) {
80030 return elt['Identifier'] == config['layer'];
80031 });
80032 if (l === null) {
80033 return null;
80034 }
80035 var tileMatrixSets = wmtsCap['Contents']['TileMatrixSet'];
80036 var idx, matrixSet, matrixLimits;
80037 if (l['TileMatrixSetLink'].length > 1) {
80038 if ('projection' in config) {
80039 idx = ol.array.findIndex(l['TileMatrixSetLink'],
80040 function(elt, index, array) {
80041 var tileMatrixSet = ol.array.find(tileMatrixSets, function(el) {
80042 return el['Identifier'] == elt['TileMatrixSet'];
80043 });
80044 var supportedCRS = tileMatrixSet['SupportedCRS'].replace(/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3');
80045 var proj1 = ol.proj.get(supportedCRS);
80046 var proj2 = ol.proj.get(config['projection']);
80047 if (proj1 && proj2) {
80048 return ol.proj.equivalent(proj1, proj2);
80049 } else {
80050 return supportedCRS == config['projection'];
80051 }
80052 });
80053 } else {
80054 idx = ol.array.findIndex(l['TileMatrixSetLink'],
80055 function(elt, index, array) {
80056 return elt['TileMatrixSet'] == config['matrixSet'];
80057 });
80058 }
80059 } else {
80060 idx = 0;
80061 }
80062 if (idx < 0) {
80063 idx = 0;
80064 }
80065 matrixSet = /** @type {string} */
80066 (l['TileMatrixSetLink'][idx]['TileMatrixSet']);
80067 matrixLimits = /** @type {Array.<Object>} */
80068 (l['TileMatrixSetLink'][idx]['TileMatrixSetLimits']);
80069
80070 var format = /** @type {string} */ (l['Format'][0]);
80071 if ('format' in config) {
80072 format = config['format'];
80073 }
80074 idx = ol.array.findIndex(l['Style'], function(elt, index, array) {
80075 if ('style' in config) {
80076 return elt['Title'] == config['style'];
80077 } else {
80078 return elt['isDefault'];
80079 }
80080 });
80081 if (idx < 0) {
80082 idx = 0;
80083 }
80084 var style = /** @type {string} */ (l['Style'][idx]['Identifier']);
80085
80086 var dimensions = {};
80087 if ('Dimension' in l) {
80088 l['Dimension'].forEach(function(elt, index, array) {
80089 var key = elt['Identifier'];
80090 var value = elt['Default'];
80091 if (value === undefined) {
80092 value = elt['Value'][0];
80093 }
80094 dimensions[key] = value;
80095 });
80096 }
80097
80098 var matrixSets = wmtsCap['Contents']['TileMatrixSet'];
80099 var matrixSetObj = ol.array.find(matrixSets, function(elt, index, array) {
80100 return elt['Identifier'] == matrixSet;
80101 });
80102
80103 var projection;
80104 if ('projection' in config) {
80105 projection = ol.proj.get(config['projection']);
80106 } else {
80107 projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace(
80108 /urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
80109 }
80110
80111 var wgs84BoundingBox = l['WGS84BoundingBox'];
80112 var extent, wrapX;
80113 if (wgs84BoundingBox !== undefined) {
80114 var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent();
80115 wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] &&
80116 wgs84BoundingBox[2] == wgs84ProjectionExtent[2]);
80117 extent = ol.proj.transformExtent(
80118 wgs84BoundingBox, 'EPSG:4326', projection);
80119 var projectionExtent = projection.getExtent();
80120 if (projectionExtent) {
80121 // If possible, do a sanity check on the extent - it should never be
80122 // bigger than the validity extent of the projection of a matrix set.
80123 if (!ol.extent.containsExtent(projectionExtent, extent)) {
80124 extent = undefined;
80125 }
80126 }
80127 }
80128
80129 var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
80130 matrixSetObj, extent, matrixLimits);
80131
80132 /** @type {!Array.<string>} */
80133 var urls = [];
80134 var requestEncoding = config['requestEncoding'];
80135 requestEncoding = requestEncoding !== undefined ? requestEncoding : '';
80136
80137 if ('OperationsMetadata' in wmtsCap && 'GetTile' in wmtsCap['OperationsMetadata']) {
80138 var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get'];
80139
80140 for (var i = 0, ii = gets.length; i < ii; ++i) {
80141 var constraint = ol.array.find(gets[i]['Constraint'], function(element) {
80142 return element['name'] == 'GetEncoding';
80143 });
80144 var encodings = constraint['AllowedValues']['Value'];
80145
80146 if (requestEncoding === '') {
80147 // requestEncoding not provided, use the first encoding from the list
80148 requestEncoding = encodings[0];
80149 }
80150 if (requestEncoding === ol.source.WMTSRequestEncoding.KVP) {
80151 if (ol.array.includes(encodings, ol.source.WMTSRequestEncoding.KVP)) {
80152 urls.push(/** @type {string} */ (gets[i]['href']));
80153 }
80154 } else {
80155 break;
80156 }
80157 }
80158 }
80159 if (urls.length === 0) {
80160 requestEncoding = ol.source.WMTSRequestEncoding.REST;
80161 l['ResourceURL'].forEach(function(element) {
80162 if (element['resourceType'] === 'tile') {
80163 format = element['format'];
80164 urls.push(/** @type {string} */ (element['template']));
80165 }
80166 });
80167 }
80168
80169 return {
80170 urls: urls,
80171 layer: config['layer'],
80172 matrixSet: matrixSet,
80173 format: format,
80174 projection: projection,
80175 requestEncoding: requestEncoding,
80176 tileGrid: tileGrid,
80177 style: style,
80178 dimensions: dimensions,
80179 wrapX: wrapX,
80180 crossOrigin: config['crossOrigin']
80181 };
80182};
80183
80184goog.provide('ol.source.Zoomify');
80185
80186goog.require('ol');
80187goog.require('ol.ImageTile');
80188goog.require('ol.TileState');
80189goog.require('ol.TileUrlFunction');
80190goog.require('ol.asserts');
80191goog.require('ol.dom');
80192goog.require('ol.extent');
80193goog.require('ol.source.TileImage');
80194goog.require('ol.tilegrid.TileGrid');
80195
80196
80197/**
80198 * @classdesc
80199 * Layer source for tile data in Zoomify format.
80200 *
80201 * @constructor
80202 * @extends {ol.source.TileImage}
80203 * @param {olx.source.ZoomifyOptions=} opt_options Options.
80204 * @api
80205 */
80206ol.source.Zoomify = function(opt_options) {
80207
80208 var options = opt_options || {};
80209
80210 var size = options.size;
80211 var tierSizeCalculation = options.tierSizeCalculation !== undefined ?
80212 options.tierSizeCalculation :
80213 ol.source.Zoomify.TierSizeCalculation_.DEFAULT;
80214
80215 var imageWidth = size[0];
80216 var imageHeight = size[1];
80217 var tierSizeInTiles = [];
80218 var tileSize = ol.DEFAULT_TILE_SIZE;
80219
80220 switch (tierSizeCalculation) {
80221 case ol.source.Zoomify.TierSizeCalculation_.DEFAULT:
80222 while (imageWidth > tileSize || imageHeight > tileSize) {
80223 tierSizeInTiles.push([
80224 Math.ceil(imageWidth / tileSize),
80225 Math.ceil(imageHeight / tileSize)
80226 ]);
80227 tileSize += tileSize;
80228 }
80229 break;
80230 case ol.source.Zoomify.TierSizeCalculation_.TRUNCATED:
80231 var width = imageWidth;
80232 var height = imageHeight;
80233 while (width > tileSize || height > tileSize) {
80234 tierSizeInTiles.push([
80235 Math.ceil(width / tileSize),
80236 Math.ceil(height / tileSize)
80237 ]);
80238 width >>= 1;
80239 height >>= 1;
80240 }
80241 break;
80242 default:
80243 ol.asserts.assert(false, 53); // Unknown `tierSizeCalculation` configured
80244 break;
80245 }
80246
80247 tierSizeInTiles.push([1, 1]);
80248 tierSizeInTiles.reverse();
80249
80250 var resolutions = [1];
80251 var tileCountUpToTier = [0];
80252 var i, ii;
80253 for (i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
80254 resolutions.push(1 << i);
80255 tileCountUpToTier.push(
80256 tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
80257 tileCountUpToTier[i - 1]
80258 );
80259 }
80260 resolutions.reverse();
80261
80262 var extent = [0, -size[1], size[0], 0];
80263 var tileGrid = new ol.tilegrid.TileGrid({
80264 extent: extent,
80265 origin: ol.extent.getTopLeft(extent),
80266 resolutions: resolutions
80267 });
80268
80269 var url = options.url;
80270 if (url && url.indexOf('{TileGroup}') == -1) {
80271 url += '{TileGroup}/{z}-{x}-{y}.jpg';
80272 }
80273 var urls = ol.TileUrlFunction.expandUrl(url);
80274
80275 /**
80276 * @param {string} template Template.
80277 * @return {ol.TileUrlFunctionType} Tile URL function.
80278 */
80279 function createFromTemplate(template) {
80280
80281 return (
80282 /**
80283 * @param {ol.TileCoord} tileCoord Tile Coordinate.
80284 * @param {number} pixelRatio Pixel ratio.
80285 * @param {ol.proj.Projection} projection Projection.
80286 * @return {string|undefined} Tile URL.
80287 */
80288 function(tileCoord, pixelRatio, projection) {
80289 if (!tileCoord) {
80290 return undefined;
80291 } else {
80292 var tileCoordZ = tileCoord[0];
80293 var tileCoordX = tileCoord[1];
80294 var tileCoordY = -tileCoord[2] - 1;
80295 var tileIndex =
80296 tileCoordX +
80297 tileCoordY * tierSizeInTiles[tileCoordZ][0] +
80298 tileCountUpToTier[tileCoordZ];
80299 var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0;
80300 var localContext = {
80301 'z': tileCoordZ,
80302 'x': tileCoordX,
80303 'y': tileCoordY,
80304 'TileGroup': 'TileGroup' + tileGroup
80305 };
80306 return template.replace(/\{(\w+?)\}/g, function(m, p) {
80307 return localContext[p];
80308 });
80309 }
80310 });
80311 }
80312
80313 var tileUrlFunction = ol.TileUrlFunction.createFromTileUrlFunctions(urls.map(createFromTemplate));
80314
80315 ol.source.TileImage.call(this, {
80316 attributions: options.attributions,
80317 cacheSize: options.cacheSize,
80318 crossOrigin: options.crossOrigin,
80319 logo: options.logo,
80320 projection: options.projection,
80321 reprojectionErrorThreshold: options.reprojectionErrorThreshold,
80322 tileClass: ol.source.Zoomify.Tile_,
80323 tileGrid: tileGrid,
80324 tileUrlFunction: tileUrlFunction
80325 });
80326
80327};
80328ol.inherits(ol.source.Zoomify, ol.source.TileImage);
80329
80330
80331/**
80332 * @constructor
80333 * @extends {ol.ImageTile}
80334 * @param {ol.TileCoord} tileCoord Tile coordinate.
80335 * @param {ol.TileState} state State.
80336 * @param {string} src Image source URI.
80337 * @param {?string} crossOrigin Cross origin.
80338 * @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
80339 * @private
80340 */
80341ol.source.Zoomify.Tile_ = function(
80342 tileCoord, state, src, crossOrigin, tileLoadFunction) {
80343
80344 ol.ImageTile.call(this, tileCoord, state, src, crossOrigin, tileLoadFunction);
80345
80346 /**
80347 * @private
80348 * @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement}
80349 */
80350 this.zoomifyImage_ = null;
80351
80352};
80353ol.inherits(ol.source.Zoomify.Tile_, ol.ImageTile);
80354
80355
80356/**
80357 * @inheritDoc
80358 */
80359ol.source.Zoomify.Tile_.prototype.getImage = function() {
80360 if (this.zoomifyImage_) {
80361 return this.zoomifyImage_;
80362 }
80363 var tileSize = ol.DEFAULT_TILE_SIZE;
80364 var image = ol.ImageTile.prototype.getImage.call(this);
80365 if (this.state == ol.TileState.LOADED) {
80366 if (image.width == tileSize && image.height == tileSize) {
80367 this.zoomifyImage_ = image;
80368 return image;
80369 } else {
80370 var context = ol.dom.createCanvasContext2D(tileSize, tileSize);
80371 context.drawImage(image, 0, 0);
80372 this.zoomifyImage_ = context.canvas;
80373 return context.canvas;
80374 }
80375 } else {
80376 return image;
80377 }
80378};
80379
80380
80381/**
80382 * @enum {string}
80383 * @private
80384 */
80385ol.source.Zoomify.TierSizeCalculation_ = {
80386 DEFAULT: 'default',
80387 TRUNCATED: 'truncated'
80388};
80389
80390// Copyright 2009 The Closure Library Authors.
80391// All Rights Reserved.
80392//
80393// Licensed under the Apache License, Version 2.0 (the "License");
80394// you may not use this file except in compliance with the License.
80395// You may obtain a copy of the License at
80396//
80397// http://www.apache.org/licenses/LICENSE-2.0
80398//
80399// Unless required by applicable law or agreed to in writing, software
80400// distributed under the License is distributed on an "AS-IS" BASIS,
80401// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
80402// See the License for the specific language governing permissions and
80403// limitations under the License.
80404//
80405// This file has been auto-generated by GenJsDeps, please do not edit.
80406
80407goog.addDependency(
80408 'demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'],
80409 ['goog.ui.equation.EquationEditorDialog']);
80410goog.addDependency(
80411 'demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'],
80412 ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']);
80413goog.addDependency(
80414 'demos/editor/helloworlddialog.js',
80415 [
80416 'goog.demos.editor.HelloWorldDialog',
80417 'goog.demos.editor.HelloWorldDialog.OkEvent'
80418 ],
80419 [
80420 'goog.dom.TagName', 'goog.events.Event', 'goog.string',
80421 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder',
80422 'goog.ui.editor.AbstractDialog.EventType'
80423 ]);
80424goog.addDependency(
80425 'demos/editor/helloworlddialogplugin.js',
80426 [
80427 'goog.demos.editor.HelloWorldDialogPlugin',
80428 'goog.demos.editor.HelloWorldDialogPlugin.Command'
80429 ],
80430 [
80431 'goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName',
80432 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range',
80433 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType'
80434 ]);
80435
80436/**
80437 * @fileoverview Custom exports file.
80438 * @suppress {checkVars,extraRequire}
80439 */
80440
80441goog.require('ol');
80442goog.require('ol.AssertionError');
80443goog.require('ol.Attribution');
80444goog.require('ol.Collection');
80445goog.require('ol.DeviceOrientation');
80446goog.require('ol.Feature');
80447goog.require('ol.Geolocation');
80448goog.require('ol.Graticule');
80449goog.require('ol.Image');
80450goog.require('ol.ImageTile');
80451goog.require('ol.Kinetic');
80452goog.require('ol.Map');
80453goog.require('ol.MapBrowserEvent');
80454goog.require('ol.MapEvent');
80455goog.require('ol.Object');
80456goog.require('ol.Observable');
80457goog.require('ol.Overlay');
80458goog.require('ol.Sphere');
80459goog.require('ol.Tile');
80460goog.require('ol.VectorTile');
80461goog.require('ol.View');
80462goog.require('ol.color');
80463goog.require('ol.colorlike');
80464goog.require('ol.control');
80465goog.require('ol.control.Attribution');
80466goog.require('ol.control.Control');
80467goog.require('ol.control.FullScreen');
80468goog.require('ol.control.MousePosition');
80469goog.require('ol.control.OverviewMap');
80470goog.require('ol.control.Rotate');
80471goog.require('ol.control.ScaleLine');
80472goog.require('ol.control.Zoom');
80473goog.require('ol.control.ZoomSlider');
80474goog.require('ol.control.ZoomToExtent');
80475goog.require('ol.coordinate');
80476goog.require('ol.easing');
80477goog.require('ol.events.Event');
80478goog.require('ol.events.condition');
80479goog.require('ol.extent');
80480goog.require('ol.featureloader');
80481goog.require('ol.format.EsriJSON');
80482goog.require('ol.format.Feature');
80483goog.require('ol.format.GML');
80484goog.require('ol.format.GML2');
80485goog.require('ol.format.GML3');
80486goog.require('ol.format.GMLBase');
80487goog.require('ol.format.GPX');
80488goog.require('ol.format.GeoJSON');
80489goog.require('ol.format.IGC');
80490goog.require('ol.format.KML');
80491goog.require('ol.format.MVT');
80492goog.require('ol.format.OSMXML');
80493goog.require('ol.format.Polyline');
80494goog.require('ol.format.TopoJSON');
80495goog.require('ol.format.WFS');
80496goog.require('ol.format.WKT');
80497goog.require('ol.format.WMSCapabilities');
80498goog.require('ol.format.WMSGetFeatureInfo');
80499goog.require('ol.format.WMTSCapabilities');
80500goog.require('ol.format.filter');
80501goog.require('ol.format.filter.And');
80502goog.require('ol.format.filter.Bbox');
80503goog.require('ol.format.filter.Comparison');
80504goog.require('ol.format.filter.ComparisonBinary');
80505goog.require('ol.format.filter.During');
80506goog.require('ol.format.filter.EqualTo');
80507goog.require('ol.format.filter.Filter');
80508goog.require('ol.format.filter.GreaterThan');
80509goog.require('ol.format.filter.GreaterThanOrEqualTo');
80510goog.require('ol.format.filter.Intersects');
80511goog.require('ol.format.filter.IsBetween');
80512goog.require('ol.format.filter.IsLike');
80513goog.require('ol.format.filter.IsNull');
80514goog.require('ol.format.filter.LessThan');
80515goog.require('ol.format.filter.LessThanOrEqualTo');
80516goog.require('ol.format.filter.Not');
80517goog.require('ol.format.filter.NotEqualTo');
80518goog.require('ol.format.filter.Or');
80519goog.require('ol.format.filter.Spatial');
80520goog.require('ol.format.filter.Within');
80521goog.require('ol.geom.Circle');
80522goog.require('ol.geom.Geometry');
80523goog.require('ol.geom.GeometryCollection');
80524goog.require('ol.geom.LineString');
80525goog.require('ol.geom.LinearRing');
80526goog.require('ol.geom.MultiLineString');
80527goog.require('ol.geom.MultiPoint');
80528goog.require('ol.geom.MultiPolygon');
80529goog.require('ol.geom.Point');
80530goog.require('ol.geom.Polygon');
80531goog.require('ol.geom.SimpleGeometry');
80532goog.require('ol.has');
80533goog.require('ol.interaction');
80534goog.require('ol.interaction.DoubleClickZoom');
80535goog.require('ol.interaction.DragAndDrop');
80536goog.require('ol.interaction.DragBox');
80537goog.require('ol.interaction.DragPan');
80538goog.require('ol.interaction.DragRotate');
80539goog.require('ol.interaction.DragRotateAndZoom');
80540goog.require('ol.interaction.DragZoom');
80541goog.require('ol.interaction.Draw');
80542goog.require('ol.interaction.Extent');
80543goog.require('ol.interaction.Interaction');
80544goog.require('ol.interaction.KeyboardPan');
80545goog.require('ol.interaction.KeyboardZoom');
80546goog.require('ol.interaction.Modify');
80547goog.require('ol.interaction.MouseWheelZoom');
80548goog.require('ol.interaction.PinchRotate');
80549goog.require('ol.interaction.PinchZoom');
80550goog.require('ol.interaction.Pointer');
80551goog.require('ol.interaction.Select');
80552goog.require('ol.interaction.Snap');
80553goog.require('ol.interaction.Translate');
80554goog.require('ol.layer.Base');
80555goog.require('ol.layer.Group');
80556goog.require('ol.layer.Heatmap');
80557goog.require('ol.layer.Image');
80558goog.require('ol.layer.Layer');
80559goog.require('ol.layer.Tile');
80560goog.require('ol.layer.Vector');
80561goog.require('ol.layer.VectorTile');
80562goog.require('ol.loadingstrategy');
80563goog.require('ol.proj');
80564goog.require('ol.proj.Projection');
80565goog.require('ol.proj.Units');
80566goog.require('ol.proj.common');
80567goog.require('ol.render');
80568goog.require('ol.render.Event');
80569goog.require('ol.render.Feature');
80570goog.require('ol.render.VectorContext');
80571goog.require('ol.render.canvas.Immediate');
80572goog.require('ol.render.webgl.Immediate');
80573goog.require('ol.size');
80574goog.require('ol.source.BingMaps');
80575goog.require('ol.source.CartoDB');
80576goog.require('ol.source.Cluster');
80577goog.require('ol.source.Image');
80578goog.require('ol.source.ImageArcGISRest');
80579goog.require('ol.source.ImageCanvas');
80580goog.require('ol.source.ImageMapGuide');
80581goog.require('ol.source.ImageStatic');
80582goog.require('ol.source.ImageVector');
80583goog.require('ol.source.ImageWMS');
80584goog.require('ol.source.OSM');
80585goog.require('ol.source.Raster');
80586goog.require('ol.source.Source');
80587goog.require('ol.source.Stamen');
80588goog.require('ol.source.Tile');
80589goog.require('ol.source.TileArcGISRest');
80590goog.require('ol.source.TileDebug');
80591goog.require('ol.source.TileImage');
80592goog.require('ol.source.TileJSON');
80593goog.require('ol.source.TileUTFGrid');
80594goog.require('ol.source.TileWMS');
80595goog.require('ol.source.UrlTile');
80596goog.require('ol.source.Vector');
80597goog.require('ol.source.VectorTile');
80598goog.require('ol.source.WMTS');
80599goog.require('ol.source.XYZ');
80600goog.require('ol.source.Zoomify');
80601goog.require('ol.style.AtlasManager');
80602goog.require('ol.style.Circle');
80603goog.require('ol.style.Fill');
80604goog.require('ol.style.Icon');
80605goog.require('ol.style.Image');
80606goog.require('ol.style.RegularShape');
80607goog.require('ol.style.Stroke');
80608goog.require('ol.style.Style');
80609goog.require('ol.style.Text');
80610goog.require('ol.tilegrid');
80611goog.require('ol.tilegrid.TileGrid');
80612goog.require('ol.tilegrid.WMTS');
80613goog.require('ol.webgl.Context');
80614goog.require('ol.xml');
80615
80616
80617
80618goog.exportProperty(
80619 ol.AssertionError.prototype,
80620 'code',
80621 ol.AssertionError.prototype.code);
80622
80623goog.exportSymbol(
80624 'ol.Attribution',
80625 ol.Attribution,
80626 OPENLAYERS);
80627
80628goog.exportProperty(
80629 ol.Attribution.prototype,
80630 'getHTML',
80631 ol.Attribution.prototype.getHTML);
80632
80633goog.exportSymbol(
80634 'ol.Collection',
80635 ol.Collection,
80636 OPENLAYERS);
80637
80638goog.exportProperty(
80639 ol.Collection.prototype,
80640 'clear',
80641 ol.Collection.prototype.clear);
80642
80643goog.exportProperty(
80644 ol.Collection.prototype,
80645 'extend',
80646 ol.Collection.prototype.extend);
80647
80648goog.exportProperty(
80649 ol.Collection.prototype,
80650 'forEach',
80651 ol.Collection.prototype.forEach);
80652
80653goog.exportProperty(
80654 ol.Collection.prototype,
80655 'getArray',
80656 ol.Collection.prototype.getArray);
80657
80658goog.exportProperty(
80659 ol.Collection.prototype,
80660 'item',
80661 ol.Collection.prototype.item);
80662
80663goog.exportProperty(
80664 ol.Collection.prototype,
80665 'getLength',
80666 ol.Collection.prototype.getLength);
80667
80668goog.exportProperty(
80669 ol.Collection.prototype,
80670 'insertAt',
80671 ol.Collection.prototype.insertAt);
80672
80673goog.exportProperty(
80674 ol.Collection.prototype,
80675 'pop',
80676 ol.Collection.prototype.pop);
80677
80678goog.exportProperty(
80679 ol.Collection.prototype,
80680 'push',
80681 ol.Collection.prototype.push);
80682
80683goog.exportProperty(
80684 ol.Collection.prototype,
80685 'remove',
80686 ol.Collection.prototype.remove);
80687
80688goog.exportProperty(
80689 ol.Collection.prototype,
80690 'removeAt',
80691 ol.Collection.prototype.removeAt);
80692
80693goog.exportProperty(
80694 ol.Collection.prototype,
80695 'setAt',
80696 ol.Collection.prototype.setAt);
80697
80698goog.exportProperty(
80699 ol.Collection.Event.prototype,
80700 'element',
80701 ol.Collection.Event.prototype.element);
80702
80703goog.exportSymbol(
80704 'ol.color.asArray',
80705 ol.color.asArray,
80706 OPENLAYERS);
80707
80708goog.exportSymbol(
80709 'ol.color.asString',
80710 ol.color.asString,
80711 OPENLAYERS);
80712
80713goog.exportSymbol(
80714 'ol.colorlike.asColorLike',
80715 ol.colorlike.asColorLike,
80716 OPENLAYERS);
80717
80718goog.exportSymbol(
80719 'ol.control.defaults',
80720 ol.control.defaults,
80721 OPENLAYERS);
80722
80723goog.exportSymbol(
80724 'ol.coordinate.add',
80725 ol.coordinate.add,
80726 OPENLAYERS);
80727
80728goog.exportSymbol(
80729 'ol.coordinate.createStringXY',
80730 ol.coordinate.createStringXY,
80731 OPENLAYERS);
80732
80733goog.exportSymbol(
80734 'ol.coordinate.format',
80735 ol.coordinate.format,
80736 OPENLAYERS);
80737
80738goog.exportSymbol(
80739 'ol.coordinate.rotate',
80740 ol.coordinate.rotate,
80741 OPENLAYERS);
80742
80743goog.exportSymbol(
80744 'ol.coordinate.toStringHDMS',
80745 ol.coordinate.toStringHDMS,
80746 OPENLAYERS);
80747
80748goog.exportSymbol(
80749 'ol.coordinate.toStringXY',
80750 ol.coordinate.toStringXY,
80751 OPENLAYERS);
80752
80753goog.exportSymbol(
80754 'ol.DeviceOrientation',
80755 ol.DeviceOrientation,
80756 OPENLAYERS);
80757
80758goog.exportProperty(
80759 ol.DeviceOrientation.prototype,
80760 'getAlpha',
80761 ol.DeviceOrientation.prototype.getAlpha);
80762
80763goog.exportProperty(
80764 ol.DeviceOrientation.prototype,
80765 'getBeta',
80766 ol.DeviceOrientation.prototype.getBeta);
80767
80768goog.exportProperty(
80769 ol.DeviceOrientation.prototype,
80770 'getGamma',
80771 ol.DeviceOrientation.prototype.getGamma);
80772
80773goog.exportProperty(
80774 ol.DeviceOrientation.prototype,
80775 'getHeading',
80776 ol.DeviceOrientation.prototype.getHeading);
80777
80778goog.exportProperty(
80779 ol.DeviceOrientation.prototype,
80780 'getTracking',
80781 ol.DeviceOrientation.prototype.getTracking);
80782
80783goog.exportProperty(
80784 ol.DeviceOrientation.prototype,
80785 'setTracking',
80786 ol.DeviceOrientation.prototype.setTracking);
80787
80788goog.exportSymbol(
80789 'ol.easing.easeIn',
80790 ol.easing.easeIn,
80791 OPENLAYERS);
80792
80793goog.exportSymbol(
80794 'ol.easing.easeOut',
80795 ol.easing.easeOut,
80796 OPENLAYERS);
80797
80798goog.exportSymbol(
80799 'ol.easing.inAndOut',
80800 ol.easing.inAndOut,
80801 OPENLAYERS);
80802
80803goog.exportSymbol(
80804 'ol.easing.linear',
80805 ol.easing.linear,
80806 OPENLAYERS);
80807
80808goog.exportSymbol(
80809 'ol.easing.upAndDown',
80810 ol.easing.upAndDown,
80811 OPENLAYERS);
80812
80813goog.exportSymbol(
80814 'ol.extent.boundingExtent',
80815 ol.extent.boundingExtent,
80816 OPENLAYERS);
80817
80818goog.exportSymbol(
80819 'ol.extent.buffer',
80820 ol.extent.buffer,
80821 OPENLAYERS);
80822
80823goog.exportSymbol(
80824 'ol.extent.containsCoordinate',
80825 ol.extent.containsCoordinate,
80826 OPENLAYERS);
80827
80828goog.exportSymbol(
80829 'ol.extent.containsExtent',
80830 ol.extent.containsExtent,
80831 OPENLAYERS);
80832
80833goog.exportSymbol(
80834 'ol.extent.containsXY',
80835 ol.extent.containsXY,
80836 OPENLAYERS);
80837
80838goog.exportSymbol(
80839 'ol.extent.createEmpty',
80840 ol.extent.createEmpty,
80841 OPENLAYERS);
80842
80843goog.exportSymbol(
80844 'ol.extent.equals',
80845 ol.extent.equals,
80846 OPENLAYERS);
80847
80848goog.exportSymbol(
80849 'ol.extent.extend',
80850 ol.extent.extend,
80851 OPENLAYERS);
80852
80853goog.exportSymbol(
80854 'ol.extent.getArea',
80855 ol.extent.getArea,
80856 OPENLAYERS);
80857
80858goog.exportSymbol(
80859 'ol.extent.getBottomLeft',
80860 ol.extent.getBottomLeft,
80861 OPENLAYERS);
80862
80863goog.exportSymbol(
80864 'ol.extent.getBottomRight',
80865 ol.extent.getBottomRight,
80866 OPENLAYERS);
80867
80868goog.exportSymbol(
80869 'ol.extent.getCenter',
80870 ol.extent.getCenter,
80871 OPENLAYERS);
80872
80873goog.exportSymbol(
80874 'ol.extent.getHeight',
80875 ol.extent.getHeight,
80876 OPENLAYERS);
80877
80878goog.exportSymbol(
80879 'ol.extent.getIntersection',
80880 ol.extent.getIntersection,
80881 OPENLAYERS);
80882
80883goog.exportSymbol(
80884 'ol.extent.getSize',
80885 ol.extent.getSize,
80886 OPENLAYERS);
80887
80888goog.exportSymbol(
80889 'ol.extent.getTopLeft',
80890 ol.extent.getTopLeft,
80891 OPENLAYERS);
80892
80893goog.exportSymbol(
80894 'ol.extent.getTopRight',
80895 ol.extent.getTopRight,
80896 OPENLAYERS);
80897
80898goog.exportSymbol(
80899 'ol.extent.getWidth',
80900 ol.extent.getWidth,
80901 OPENLAYERS);
80902
80903goog.exportSymbol(
80904 'ol.extent.intersects',
80905 ol.extent.intersects,
80906 OPENLAYERS);
80907
80908goog.exportSymbol(
80909 'ol.extent.isEmpty',
80910 ol.extent.isEmpty,
80911 OPENLAYERS);
80912
80913goog.exportSymbol(
80914 'ol.extent.applyTransform',
80915 ol.extent.applyTransform,
80916 OPENLAYERS);
80917
80918goog.exportSymbol(
80919 'ol.Feature',
80920 ol.Feature,
80921 OPENLAYERS);
80922
80923goog.exportProperty(
80924 ol.Feature.prototype,
80925 'clone',
80926 ol.Feature.prototype.clone);
80927
80928goog.exportProperty(
80929 ol.Feature.prototype,
80930 'getGeometry',
80931 ol.Feature.prototype.getGeometry);
80932
80933goog.exportProperty(
80934 ol.Feature.prototype,
80935 'getId',
80936 ol.Feature.prototype.getId);
80937
80938goog.exportProperty(
80939 ol.Feature.prototype,
80940 'getGeometryName',
80941 ol.Feature.prototype.getGeometryName);
80942
80943goog.exportProperty(
80944 ol.Feature.prototype,
80945 'getStyle',
80946 ol.Feature.prototype.getStyle);
80947
80948goog.exportProperty(
80949 ol.Feature.prototype,
80950 'getStyleFunction',
80951 ol.Feature.prototype.getStyleFunction);
80952
80953goog.exportProperty(
80954 ol.Feature.prototype,
80955 'setGeometry',
80956 ol.Feature.prototype.setGeometry);
80957
80958goog.exportProperty(
80959 ol.Feature.prototype,
80960 'setStyle',
80961 ol.Feature.prototype.setStyle);
80962
80963goog.exportProperty(
80964 ol.Feature.prototype,
80965 'setId',
80966 ol.Feature.prototype.setId);
80967
80968goog.exportProperty(
80969 ol.Feature.prototype,
80970 'setGeometryName',
80971 ol.Feature.prototype.setGeometryName);
80972
80973goog.exportSymbol(
80974 'ol.featureloader.xhr',
80975 ol.featureloader.xhr,
80976 OPENLAYERS);
80977
80978goog.exportSymbol(
80979 'ol.Geolocation',
80980 ol.Geolocation,
80981 OPENLAYERS);
80982
80983goog.exportProperty(
80984 ol.Geolocation.prototype,
80985 'getAccuracy',
80986 ol.Geolocation.prototype.getAccuracy);
80987
80988goog.exportProperty(
80989 ol.Geolocation.prototype,
80990 'getAccuracyGeometry',
80991 ol.Geolocation.prototype.getAccuracyGeometry);
80992
80993goog.exportProperty(
80994 ol.Geolocation.prototype,
80995 'getAltitude',
80996 ol.Geolocation.prototype.getAltitude);
80997
80998goog.exportProperty(
80999 ol.Geolocation.prototype,
81000 'getAltitudeAccuracy',
81001 ol.Geolocation.prototype.getAltitudeAccuracy);
81002
81003goog.exportProperty(
81004 ol.Geolocation.prototype,
81005 'getHeading',
81006 ol.Geolocation.prototype.getHeading);
81007
81008goog.exportProperty(
81009 ol.Geolocation.prototype,
81010 'getPosition',
81011 ol.Geolocation.prototype.getPosition);
81012
81013goog.exportProperty(
81014 ol.Geolocation.prototype,
81015 'getProjection',
81016 ol.Geolocation.prototype.getProjection);
81017
81018goog.exportProperty(
81019 ol.Geolocation.prototype,
81020 'getSpeed',
81021 ol.Geolocation.prototype.getSpeed);
81022
81023goog.exportProperty(
81024 ol.Geolocation.prototype,
81025 'getTracking',
81026 ol.Geolocation.prototype.getTracking);
81027
81028goog.exportProperty(
81029 ol.Geolocation.prototype,
81030 'getTrackingOptions',
81031 ol.Geolocation.prototype.getTrackingOptions);
81032
81033goog.exportProperty(
81034 ol.Geolocation.prototype,
81035 'setProjection',
81036 ol.Geolocation.prototype.setProjection);
81037
81038goog.exportProperty(
81039 ol.Geolocation.prototype,
81040 'setTracking',
81041 ol.Geolocation.prototype.setTracking);
81042
81043goog.exportProperty(
81044 ol.Geolocation.prototype,
81045 'setTrackingOptions',
81046 ol.Geolocation.prototype.setTrackingOptions);
81047
81048goog.exportSymbol(
81049 'ol.Graticule',
81050 ol.Graticule,
81051 OPENLAYERS);
81052
81053goog.exportProperty(
81054 ol.Graticule.prototype,
81055 'getMap',
81056 ol.Graticule.prototype.getMap);
81057
81058goog.exportProperty(
81059 ol.Graticule.prototype,
81060 'getMeridians',
81061 ol.Graticule.prototype.getMeridians);
81062
81063goog.exportProperty(
81064 ol.Graticule.prototype,
81065 'getParallels',
81066 ol.Graticule.prototype.getParallels);
81067
81068goog.exportProperty(
81069 ol.Graticule.prototype,
81070 'setMap',
81071 ol.Graticule.prototype.setMap);
81072
81073goog.exportSymbol(
81074 'ol.has.DEVICE_PIXEL_RATIO',
81075 ol.has.DEVICE_PIXEL_RATIO,
81076 OPENLAYERS);
81077
81078goog.exportSymbol(
81079 'ol.has.CANVAS',
81080 ol.has.CANVAS,
81081 OPENLAYERS);
81082
81083goog.exportSymbol(
81084 'ol.has.DEVICE_ORIENTATION',
81085 ol.has.DEVICE_ORIENTATION,
81086 OPENLAYERS);
81087
81088goog.exportSymbol(
81089 'ol.has.GEOLOCATION',
81090 ol.has.GEOLOCATION,
81091 OPENLAYERS);
81092
81093goog.exportSymbol(
81094 'ol.has.TOUCH',
81095 ol.has.TOUCH,
81096 OPENLAYERS);
81097
81098goog.exportSymbol(
81099 'ol.has.WEBGL',
81100 ol.has.WEBGL,
81101 OPENLAYERS);
81102
81103goog.exportProperty(
81104 ol.Image.prototype,
81105 'getImage',
81106 ol.Image.prototype.getImage);
81107
81108goog.exportProperty(
81109 ol.Image.prototype,
81110 'load',
81111 ol.Image.prototype.load);
81112
81113goog.exportProperty(
81114 ol.ImageTile.prototype,
81115 'getImage',
81116 ol.ImageTile.prototype.getImage);
81117
81118goog.exportSymbol(
81119 'ol.inherits',
81120 ol.inherits,
81121 OPENLAYERS);
81122
81123goog.exportSymbol(
81124 'ol.interaction.defaults',
81125 ol.interaction.defaults,
81126 OPENLAYERS);
81127
81128goog.exportSymbol(
81129 'ol.Kinetic',
81130 ol.Kinetic,
81131 OPENLAYERS);
81132
81133goog.exportSymbol(
81134 'ol.loadingstrategy.all',
81135 ol.loadingstrategy.all,
81136 OPENLAYERS);
81137
81138goog.exportSymbol(
81139 'ol.loadingstrategy.bbox',
81140 ol.loadingstrategy.bbox,
81141 OPENLAYERS);
81142
81143goog.exportSymbol(
81144 'ol.loadingstrategy.tile',
81145 ol.loadingstrategy.tile,
81146 OPENLAYERS);
81147
81148goog.exportSymbol(
81149 'ol.Map',
81150 ol.Map,
81151 OPENLAYERS);
81152
81153goog.exportProperty(
81154 ol.Map.prototype,
81155 'addControl',
81156 ol.Map.prototype.addControl);
81157
81158goog.exportProperty(
81159 ol.Map.prototype,
81160 'addInteraction',
81161 ol.Map.prototype.addInteraction);
81162
81163goog.exportProperty(
81164 ol.Map.prototype,
81165 'addLayer',
81166 ol.Map.prototype.addLayer);
81167
81168goog.exportProperty(
81169 ol.Map.prototype,
81170 'addOverlay',
81171 ol.Map.prototype.addOverlay);
81172
81173goog.exportProperty(
81174 ol.Map.prototype,
81175 'forEachFeatureAtPixel',
81176 ol.Map.prototype.forEachFeatureAtPixel);
81177
81178goog.exportProperty(
81179 ol.Map.prototype,
81180 'getFeaturesAtPixel',
81181 ol.Map.prototype.getFeaturesAtPixel);
81182
81183goog.exportProperty(
81184 ol.Map.prototype,
81185 'forEachLayerAtPixel',
81186 ol.Map.prototype.forEachLayerAtPixel);
81187
81188goog.exportProperty(
81189 ol.Map.prototype,
81190 'hasFeatureAtPixel',
81191 ol.Map.prototype.hasFeatureAtPixel);
81192
81193goog.exportProperty(
81194 ol.Map.prototype,
81195 'getEventCoordinate',
81196 ol.Map.prototype.getEventCoordinate);
81197
81198goog.exportProperty(
81199 ol.Map.prototype,
81200 'getEventPixel',
81201 ol.Map.prototype.getEventPixel);
81202
81203goog.exportProperty(
81204 ol.Map.prototype,
81205 'getTarget',
81206 ol.Map.prototype.getTarget);
81207
81208goog.exportProperty(
81209 ol.Map.prototype,
81210 'getTargetElement',
81211 ol.Map.prototype.getTargetElement);
81212
81213goog.exportProperty(
81214 ol.Map.prototype,
81215 'getCoordinateFromPixel',
81216 ol.Map.prototype.getCoordinateFromPixel);
81217
81218goog.exportProperty(
81219 ol.Map.prototype,
81220 'getControls',
81221 ol.Map.prototype.getControls);
81222
81223goog.exportProperty(
81224 ol.Map.prototype,
81225 'getOverlays',
81226 ol.Map.prototype.getOverlays);
81227
81228goog.exportProperty(
81229 ol.Map.prototype,
81230 'getOverlayById',
81231 ol.Map.prototype.getOverlayById);
81232
81233goog.exportProperty(
81234 ol.Map.prototype,
81235 'getInteractions',
81236 ol.Map.prototype.getInteractions);
81237
81238goog.exportProperty(
81239 ol.Map.prototype,
81240 'getLayerGroup',
81241 ol.Map.prototype.getLayerGroup);
81242
81243goog.exportProperty(
81244 ol.Map.prototype,
81245 'getLayers',
81246 ol.Map.prototype.getLayers);
81247
81248goog.exportProperty(
81249 ol.Map.prototype,
81250 'getPixelFromCoordinate',
81251 ol.Map.prototype.getPixelFromCoordinate);
81252
81253goog.exportProperty(
81254 ol.Map.prototype,
81255 'getSize',
81256 ol.Map.prototype.getSize);
81257
81258goog.exportProperty(
81259 ol.Map.prototype,
81260 'getView',
81261 ol.Map.prototype.getView);
81262
81263goog.exportProperty(
81264 ol.Map.prototype,
81265 'getViewport',
81266 ol.Map.prototype.getViewport);
81267
81268goog.exportProperty(
81269 ol.Map.prototype,
81270 'renderSync',
81271 ol.Map.prototype.renderSync);
81272
81273goog.exportProperty(
81274 ol.Map.prototype,
81275 'render',
81276 ol.Map.prototype.render);
81277
81278goog.exportProperty(
81279 ol.Map.prototype,
81280 'removeControl',
81281 ol.Map.prototype.removeControl);
81282
81283goog.exportProperty(
81284 ol.Map.prototype,
81285 'removeInteraction',
81286 ol.Map.prototype.removeInteraction);
81287
81288goog.exportProperty(
81289 ol.Map.prototype,
81290 'removeLayer',
81291 ol.Map.prototype.removeLayer);
81292
81293goog.exportProperty(
81294 ol.Map.prototype,
81295 'removeOverlay',
81296 ol.Map.prototype.removeOverlay);
81297
81298goog.exportProperty(
81299 ol.Map.prototype,
81300 'setLayerGroup',
81301 ol.Map.prototype.setLayerGroup);
81302
81303goog.exportProperty(
81304 ol.Map.prototype,
81305 'setSize',
81306 ol.Map.prototype.setSize);
81307
81308goog.exportProperty(
81309 ol.Map.prototype,
81310 'setTarget',
81311 ol.Map.prototype.setTarget);
81312
81313goog.exportProperty(
81314 ol.Map.prototype,
81315 'setView',
81316 ol.Map.prototype.setView);
81317
81318goog.exportProperty(
81319 ol.Map.prototype,
81320 'updateSize',
81321 ol.Map.prototype.updateSize);
81322
81323goog.exportProperty(
81324 ol.MapBrowserEvent.prototype,
81325 'originalEvent',
81326 ol.MapBrowserEvent.prototype.originalEvent);
81327
81328goog.exportProperty(
81329 ol.MapBrowserEvent.prototype,
81330 'pixel',
81331 ol.MapBrowserEvent.prototype.pixel);
81332
81333goog.exportProperty(
81334 ol.MapBrowserEvent.prototype,
81335 'coordinate',
81336 ol.MapBrowserEvent.prototype.coordinate);
81337
81338goog.exportProperty(
81339 ol.MapBrowserEvent.prototype,
81340 'dragging',
81341 ol.MapBrowserEvent.prototype.dragging);
81342
81343goog.exportProperty(
81344 ol.MapEvent.prototype,
81345 'map',
81346 ol.MapEvent.prototype.map);
81347
81348goog.exportProperty(
81349 ol.MapEvent.prototype,
81350 'frameState',
81351 ol.MapEvent.prototype.frameState);
81352
81353goog.exportSymbol(
81354 'ol.Object',
81355 ol.Object,
81356 OPENLAYERS);
81357
81358goog.exportProperty(
81359 ol.Object.prototype,
81360 'get',
81361 ol.Object.prototype.get);
81362
81363goog.exportProperty(
81364 ol.Object.prototype,
81365 'getKeys',
81366 ol.Object.prototype.getKeys);
81367
81368goog.exportProperty(
81369 ol.Object.prototype,
81370 'getProperties',
81371 ol.Object.prototype.getProperties);
81372
81373goog.exportProperty(
81374 ol.Object.prototype,
81375 'set',
81376 ol.Object.prototype.set);
81377
81378goog.exportProperty(
81379 ol.Object.prototype,
81380 'setProperties',
81381 ol.Object.prototype.setProperties);
81382
81383goog.exportProperty(
81384 ol.Object.prototype,
81385 'unset',
81386 ol.Object.prototype.unset);
81387
81388goog.exportProperty(
81389 ol.Object.Event.prototype,
81390 'key',
81391 ol.Object.Event.prototype.key);
81392
81393goog.exportProperty(
81394 ol.Object.Event.prototype,
81395 'oldValue',
81396 ol.Object.Event.prototype.oldValue);
81397
81398goog.exportSymbol(
81399 'ol.Observable',
81400 ol.Observable,
81401 OPENLAYERS);
81402
81403goog.exportSymbol(
81404 'ol.Observable.unByKey',
81405 ol.Observable.unByKey,
81406 OPENLAYERS);
81407
81408goog.exportProperty(
81409 ol.Observable.prototype,
81410 'changed',
81411 ol.Observable.prototype.changed);
81412
81413goog.exportProperty(
81414 ol.Observable.prototype,
81415 'dispatchEvent',
81416 ol.Observable.prototype.dispatchEvent);
81417
81418goog.exportProperty(
81419 ol.Observable.prototype,
81420 'getRevision',
81421 ol.Observable.prototype.getRevision);
81422
81423goog.exportProperty(
81424 ol.Observable.prototype,
81425 'on',
81426 ol.Observable.prototype.on);
81427
81428goog.exportProperty(
81429 ol.Observable.prototype,
81430 'once',
81431 ol.Observable.prototype.once);
81432
81433goog.exportProperty(
81434 ol.Observable.prototype,
81435 'un',
81436 ol.Observable.prototype.un);
81437
81438goog.exportSymbol(
81439 'ol.Overlay',
81440 ol.Overlay,
81441 OPENLAYERS);
81442
81443goog.exportProperty(
81444 ol.Overlay.prototype,
81445 'getElement',
81446 ol.Overlay.prototype.getElement);
81447
81448goog.exportProperty(
81449 ol.Overlay.prototype,
81450 'getId',
81451 ol.Overlay.prototype.getId);
81452
81453goog.exportProperty(
81454 ol.Overlay.prototype,
81455 'getMap',
81456 ol.Overlay.prototype.getMap);
81457
81458goog.exportProperty(
81459 ol.Overlay.prototype,
81460 'getOffset',
81461 ol.Overlay.prototype.getOffset);
81462
81463goog.exportProperty(
81464 ol.Overlay.prototype,
81465 'getPosition',
81466 ol.Overlay.prototype.getPosition);
81467
81468goog.exportProperty(
81469 ol.Overlay.prototype,
81470 'getPositioning',
81471 ol.Overlay.prototype.getPositioning);
81472
81473goog.exportProperty(
81474 ol.Overlay.prototype,
81475 'setElement',
81476 ol.Overlay.prototype.setElement);
81477
81478goog.exportProperty(
81479 ol.Overlay.prototype,
81480 'setMap',
81481 ol.Overlay.prototype.setMap);
81482
81483goog.exportProperty(
81484 ol.Overlay.prototype,
81485 'setOffset',
81486 ol.Overlay.prototype.setOffset);
81487
81488goog.exportProperty(
81489 ol.Overlay.prototype,
81490 'setPosition',
81491 ol.Overlay.prototype.setPosition);
81492
81493goog.exportProperty(
81494 ol.Overlay.prototype,
81495 'setPositioning',
81496 ol.Overlay.prototype.setPositioning);
81497
81498goog.exportSymbol(
81499 'ol.proj.METERS_PER_UNIT',
81500 ol.proj.METERS_PER_UNIT,
81501 OPENLAYERS);
81502
81503goog.exportSymbol(
81504 'ol.proj.setProj4',
81505 ol.proj.setProj4,
81506 OPENLAYERS);
81507
81508goog.exportSymbol(
81509 'ol.proj.getPointResolution',
81510 ol.proj.getPointResolution,
81511 OPENLAYERS);
81512
81513goog.exportSymbol(
81514 'ol.proj.addEquivalentProjections',
81515 ol.proj.addEquivalentProjections,
81516 OPENLAYERS);
81517
81518goog.exportSymbol(
81519 'ol.proj.addProjection',
81520 ol.proj.addProjection,
81521 OPENLAYERS);
81522
81523goog.exportSymbol(
81524 'ol.proj.addCoordinateTransforms',
81525 ol.proj.addCoordinateTransforms,
81526 OPENLAYERS);
81527
81528goog.exportSymbol(
81529 'ol.proj.fromLonLat',
81530 ol.proj.fromLonLat,
81531 OPENLAYERS);
81532
81533goog.exportSymbol(
81534 'ol.proj.toLonLat',
81535 ol.proj.toLonLat,
81536 OPENLAYERS);
81537
81538goog.exportSymbol(
81539 'ol.proj.get',
81540 ol.proj.get,
81541 OPENLAYERS);
81542
81543goog.exportSymbol(
81544 'ol.proj.equivalent',
81545 ol.proj.equivalent,
81546 OPENLAYERS);
81547
81548goog.exportSymbol(
81549 'ol.proj.getTransform',
81550 ol.proj.getTransform,
81551 OPENLAYERS);
81552
81553goog.exportSymbol(
81554 'ol.proj.transform',
81555 ol.proj.transform,
81556 OPENLAYERS);
81557
81558goog.exportSymbol(
81559 'ol.proj.transformExtent',
81560 ol.proj.transformExtent,
81561 OPENLAYERS);
81562
81563goog.exportSymbol(
81564 'ol.render.toContext',
81565 ol.render.toContext,
81566 OPENLAYERS);
81567
81568goog.exportSymbol(
81569 'ol.size.toSize',
81570 ol.size.toSize,
81571 OPENLAYERS);
81572
81573goog.exportSymbol(
81574 'ol.Sphere',
81575 ol.Sphere,
81576 OPENLAYERS);
81577
81578goog.exportProperty(
81579 ol.Sphere.prototype,
81580 'geodesicArea',
81581 ol.Sphere.prototype.geodesicArea);
81582
81583goog.exportProperty(
81584 ol.Sphere.prototype,
81585 'haversineDistance',
81586 ol.Sphere.prototype.haversineDistance);
81587
81588goog.exportSymbol(
81589 'ol.Sphere.getLength',
81590 ol.Sphere.getLength,
81591 OPENLAYERS);
81592
81593goog.exportSymbol(
81594 'ol.Sphere.getArea',
81595 ol.Sphere.getArea,
81596 OPENLAYERS);
81597
81598goog.exportProperty(
81599 ol.Tile.prototype,
81600 'getTileCoord',
81601 ol.Tile.prototype.getTileCoord);
81602
81603goog.exportProperty(
81604 ol.Tile.prototype,
81605 'load',
81606 ol.Tile.prototype.load);
81607
81608goog.exportSymbol(
81609 'ol.tilegrid.createXYZ',
81610 ol.tilegrid.createXYZ,
81611 OPENLAYERS);
81612
81613goog.exportProperty(
81614 ol.VectorTile.prototype,
81615 'getFormat',
81616 ol.VectorTile.prototype.getFormat);
81617
81618goog.exportProperty(
81619 ol.VectorTile.prototype,
81620 'getFeatures',
81621 ol.VectorTile.prototype.getFeatures);
81622
81623goog.exportProperty(
81624 ol.VectorTile.prototype,
81625 'getProjection',
81626 ol.VectorTile.prototype.getProjection);
81627
81628goog.exportProperty(
81629 ol.VectorTile.prototype,
81630 'setExtent',
81631 ol.VectorTile.prototype.setExtent);
81632
81633goog.exportProperty(
81634 ol.VectorTile.prototype,
81635 'setFeatures',
81636 ol.VectorTile.prototype.setFeatures);
81637
81638goog.exportProperty(
81639 ol.VectorTile.prototype,
81640 'setProjection',
81641 ol.VectorTile.prototype.setProjection);
81642
81643goog.exportProperty(
81644 ol.VectorTile.prototype,
81645 'setLoader',
81646 ol.VectorTile.prototype.setLoader);
81647
81648goog.exportSymbol(
81649 'ol.View',
81650 ol.View,
81651 OPENLAYERS);
81652
81653goog.exportProperty(
81654 ol.View.prototype,
81655 'animate',
81656 ol.View.prototype.animate);
81657
81658goog.exportProperty(
81659 ol.View.prototype,
81660 'getAnimating',
81661 ol.View.prototype.getAnimating);
81662
81663goog.exportProperty(
81664 ol.View.prototype,
81665 'getInteracting',
81666 ol.View.prototype.getInteracting);
81667
81668goog.exportProperty(
81669 ol.View.prototype,
81670 'cancelAnimations',
81671 ol.View.prototype.cancelAnimations);
81672
81673goog.exportProperty(
81674 ol.View.prototype,
81675 'constrainCenter',
81676 ol.View.prototype.constrainCenter);
81677
81678goog.exportProperty(
81679 ol.View.prototype,
81680 'constrainResolution',
81681 ol.View.prototype.constrainResolution);
81682
81683goog.exportProperty(
81684 ol.View.prototype,
81685 'constrainRotation',
81686 ol.View.prototype.constrainRotation);
81687
81688goog.exportProperty(
81689 ol.View.prototype,
81690 'getCenter',
81691 ol.View.prototype.getCenter);
81692
81693goog.exportProperty(
81694 ol.View.prototype,
81695 'calculateExtent',
81696 ol.View.prototype.calculateExtent);
81697
81698goog.exportProperty(
81699 ol.View.prototype,
81700 'getMaxResolution',
81701 ol.View.prototype.getMaxResolution);
81702
81703goog.exportProperty(
81704 ol.View.prototype,
81705 'getMinResolution',
81706 ol.View.prototype.getMinResolution);
81707
81708goog.exportProperty(
81709 ol.View.prototype,
81710 'getMaxZoom',
81711 ol.View.prototype.getMaxZoom);
81712
81713goog.exportProperty(
81714 ol.View.prototype,
81715 'setMaxZoom',
81716 ol.View.prototype.setMaxZoom);
81717
81718goog.exportProperty(
81719 ol.View.prototype,
81720 'getMinZoom',
81721 ol.View.prototype.getMinZoom);
81722
81723goog.exportProperty(
81724 ol.View.prototype,
81725 'setMinZoom',
81726 ol.View.prototype.setMinZoom);
81727
81728goog.exportProperty(
81729 ol.View.prototype,
81730 'getProjection',
81731 ol.View.prototype.getProjection);
81732
81733goog.exportProperty(
81734 ol.View.prototype,
81735 'getResolution',
81736 ol.View.prototype.getResolution);
81737
81738goog.exportProperty(
81739 ol.View.prototype,
81740 'getResolutions',
81741 ol.View.prototype.getResolutions);
81742
81743goog.exportProperty(
81744 ol.View.prototype,
81745 'getResolutionForExtent',
81746 ol.View.prototype.getResolutionForExtent);
81747
81748goog.exportProperty(
81749 ol.View.prototype,
81750 'getRotation',
81751 ol.View.prototype.getRotation);
81752
81753goog.exportProperty(
81754 ol.View.prototype,
81755 'getZoom',
81756 ol.View.prototype.getZoom);
81757
81758goog.exportProperty(
81759 ol.View.prototype,
81760 'getZoomForResolution',
81761 ol.View.prototype.getZoomForResolution);
81762
81763goog.exportProperty(
81764 ol.View.prototype,
81765 'getResolutionForZoom',
81766 ol.View.prototype.getResolutionForZoom);
81767
81768goog.exportProperty(
81769 ol.View.prototype,
81770 'fit',
81771 ol.View.prototype.fit);
81772
81773goog.exportProperty(
81774 ol.View.prototype,
81775 'centerOn',
81776 ol.View.prototype.centerOn);
81777
81778goog.exportProperty(
81779 ol.View.prototype,
81780 'rotate',
81781 ol.View.prototype.rotate);
81782
81783goog.exportProperty(
81784 ol.View.prototype,
81785 'setCenter',
81786 ol.View.prototype.setCenter);
81787
81788goog.exportProperty(
81789 ol.View.prototype,
81790 'setResolution',
81791 ol.View.prototype.setResolution);
81792
81793goog.exportProperty(
81794 ol.View.prototype,
81795 'setRotation',
81796 ol.View.prototype.setRotation);
81797
81798goog.exportProperty(
81799 ol.View.prototype,
81800 'setZoom',
81801 ol.View.prototype.setZoom);
81802
81803goog.exportSymbol(
81804 'ol.xml.getAllTextContent',
81805 ol.xml.getAllTextContent,
81806 OPENLAYERS);
81807
81808goog.exportSymbol(
81809 'ol.xml.parse',
81810 ol.xml.parse,
81811 OPENLAYERS);
81812
81813goog.exportProperty(
81814 ol.webgl.Context.prototype,
81815 'getGL',
81816 ol.webgl.Context.prototype.getGL);
81817
81818goog.exportProperty(
81819 ol.webgl.Context.prototype,
81820 'useProgram',
81821 ol.webgl.Context.prototype.useProgram);
81822
81823goog.exportSymbol(
81824 'ol.tilegrid.TileGrid',
81825 ol.tilegrid.TileGrid,
81826 OPENLAYERS);
81827
81828goog.exportProperty(
81829 ol.tilegrid.TileGrid.prototype,
81830 'forEachTileCoord',
81831 ol.tilegrid.TileGrid.prototype.forEachTileCoord);
81832
81833goog.exportProperty(
81834 ol.tilegrid.TileGrid.prototype,
81835 'getMaxZoom',
81836 ol.tilegrid.TileGrid.prototype.getMaxZoom);
81837
81838goog.exportProperty(
81839 ol.tilegrid.TileGrid.prototype,
81840 'getMinZoom',
81841 ol.tilegrid.TileGrid.prototype.getMinZoom);
81842
81843goog.exportProperty(
81844 ol.tilegrid.TileGrid.prototype,
81845 'getOrigin',
81846 ol.tilegrid.TileGrid.prototype.getOrigin);
81847
81848goog.exportProperty(
81849 ol.tilegrid.TileGrid.prototype,
81850 'getResolution',
81851 ol.tilegrid.TileGrid.prototype.getResolution);
81852
81853goog.exportProperty(
81854 ol.tilegrid.TileGrid.prototype,
81855 'getResolutions',
81856 ol.tilegrid.TileGrid.prototype.getResolutions);
81857
81858goog.exportProperty(
81859 ol.tilegrid.TileGrid.prototype,
81860 'getTileCoordExtent',
81861 ol.tilegrid.TileGrid.prototype.getTileCoordExtent);
81862
81863goog.exportProperty(
81864 ol.tilegrid.TileGrid.prototype,
81865 'getTileCoordForCoordAndResolution',
81866 ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndResolution);
81867
81868goog.exportProperty(
81869 ol.tilegrid.TileGrid.prototype,
81870 'getTileCoordForCoordAndZ',
81871 ol.tilegrid.TileGrid.prototype.getTileCoordForCoordAndZ);
81872
81873goog.exportProperty(
81874 ol.tilegrid.TileGrid.prototype,
81875 'getTileSize',
81876 ol.tilegrid.TileGrid.prototype.getTileSize);
81877
81878goog.exportProperty(
81879 ol.tilegrid.TileGrid.prototype,
81880 'getZForResolution',
81881 ol.tilegrid.TileGrid.prototype.getZForResolution);
81882
81883goog.exportSymbol(
81884 'ol.tilegrid.WMTS',
81885 ol.tilegrid.WMTS,
81886 OPENLAYERS);
81887
81888goog.exportProperty(
81889 ol.tilegrid.WMTS.prototype,
81890 'getMatrixIds',
81891 ol.tilegrid.WMTS.prototype.getMatrixIds);
81892
81893goog.exportSymbol(
81894 'ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet',
81895 ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet,
81896 OPENLAYERS);
81897
81898goog.exportSymbol(
81899 'ol.style.AtlasManager',
81900 ol.style.AtlasManager,
81901 OPENLAYERS);
81902
81903goog.exportSymbol(
81904 'ol.style.Circle',
81905 ol.style.Circle,
81906 OPENLAYERS);
81907
81908goog.exportProperty(
81909 ol.style.Circle.prototype,
81910 'setRadius',
81911 ol.style.Circle.prototype.setRadius);
81912
81913goog.exportSymbol(
81914 'ol.style.Fill',
81915 ol.style.Fill,
81916 OPENLAYERS);
81917
81918goog.exportProperty(
81919 ol.style.Fill.prototype,
81920 'clone',
81921 ol.style.Fill.prototype.clone);
81922
81923goog.exportProperty(
81924 ol.style.Fill.prototype,
81925 'getColor',
81926 ol.style.Fill.prototype.getColor);
81927
81928goog.exportProperty(
81929 ol.style.Fill.prototype,
81930 'setColor',
81931 ol.style.Fill.prototype.setColor);
81932
81933goog.exportSymbol(
81934 'ol.style.Icon',
81935 ol.style.Icon,
81936 OPENLAYERS);
81937
81938goog.exportProperty(
81939 ol.style.Icon.prototype,
81940 'clone',
81941 ol.style.Icon.prototype.clone);
81942
81943goog.exportProperty(
81944 ol.style.Icon.prototype,
81945 'getAnchor',
81946 ol.style.Icon.prototype.getAnchor);
81947
81948goog.exportProperty(
81949 ol.style.Icon.prototype,
81950 'getColor',
81951 ol.style.Icon.prototype.getColor);
81952
81953goog.exportProperty(
81954 ol.style.Icon.prototype,
81955 'getImage',
81956 ol.style.Icon.prototype.getImage);
81957
81958goog.exportProperty(
81959 ol.style.Icon.prototype,
81960 'getOrigin',
81961 ol.style.Icon.prototype.getOrigin);
81962
81963goog.exportProperty(
81964 ol.style.Icon.prototype,
81965 'getSrc',
81966 ol.style.Icon.prototype.getSrc);
81967
81968goog.exportProperty(
81969 ol.style.Icon.prototype,
81970 'getSize',
81971 ol.style.Icon.prototype.getSize);
81972
81973goog.exportProperty(
81974 ol.style.Icon.prototype,
81975 'load',
81976 ol.style.Icon.prototype.load);
81977
81978goog.exportSymbol(
81979 'ol.style.Image',
81980 ol.style.Image,
81981 OPENLAYERS);
81982
81983goog.exportProperty(
81984 ol.style.Image.prototype,
81985 'getOpacity',
81986 ol.style.Image.prototype.getOpacity);
81987
81988goog.exportProperty(
81989 ol.style.Image.prototype,
81990 'getRotateWithView',
81991 ol.style.Image.prototype.getRotateWithView);
81992
81993goog.exportProperty(
81994 ol.style.Image.prototype,
81995 'getRotation',
81996 ol.style.Image.prototype.getRotation);
81997
81998goog.exportProperty(
81999 ol.style.Image.prototype,
82000 'getScale',
82001 ol.style.Image.prototype.getScale);
82002
82003goog.exportProperty(
82004 ol.style.Image.prototype,
82005 'getSnapToPixel',
82006 ol.style.Image.prototype.getSnapToPixel);
82007
82008goog.exportProperty(
82009 ol.style.Image.prototype,
82010 'setOpacity',
82011 ol.style.Image.prototype.setOpacity);
82012
82013goog.exportProperty(
82014 ol.style.Image.prototype,
82015 'setRotation',
82016 ol.style.Image.prototype.setRotation);
82017
82018goog.exportProperty(
82019 ol.style.Image.prototype,
82020 'setScale',
82021 ol.style.Image.prototype.setScale);
82022
82023goog.exportSymbol(
82024 'ol.style.RegularShape',
82025 ol.style.RegularShape,
82026 OPENLAYERS);
82027
82028goog.exportProperty(
82029 ol.style.RegularShape.prototype,
82030 'clone',
82031 ol.style.RegularShape.prototype.clone);
82032
82033goog.exportProperty(
82034 ol.style.RegularShape.prototype,
82035 'getAnchor',
82036 ol.style.RegularShape.prototype.getAnchor);
82037
82038goog.exportProperty(
82039 ol.style.RegularShape.prototype,
82040 'getAngle',
82041 ol.style.RegularShape.prototype.getAngle);
82042
82043goog.exportProperty(
82044 ol.style.RegularShape.prototype,
82045 'getFill',
82046 ol.style.RegularShape.prototype.getFill);
82047
82048goog.exportProperty(
82049 ol.style.RegularShape.prototype,
82050 'getImage',
82051 ol.style.RegularShape.prototype.getImage);
82052
82053goog.exportProperty(
82054 ol.style.RegularShape.prototype,
82055 'getOrigin',
82056 ol.style.RegularShape.prototype.getOrigin);
82057
82058goog.exportProperty(
82059 ol.style.RegularShape.prototype,
82060 'getPoints',
82061 ol.style.RegularShape.prototype.getPoints);
82062
82063goog.exportProperty(
82064 ol.style.RegularShape.prototype,
82065 'getRadius',
82066 ol.style.RegularShape.prototype.getRadius);
82067
82068goog.exportProperty(
82069 ol.style.RegularShape.prototype,
82070 'getRadius2',
82071 ol.style.RegularShape.prototype.getRadius2);
82072
82073goog.exportProperty(
82074 ol.style.RegularShape.prototype,
82075 'getSize',
82076 ol.style.RegularShape.prototype.getSize);
82077
82078goog.exportProperty(
82079 ol.style.RegularShape.prototype,
82080 'getStroke',
82081 ol.style.RegularShape.prototype.getStroke);
82082
82083goog.exportSymbol(
82084 'ol.style.Stroke',
82085 ol.style.Stroke,
82086 OPENLAYERS);
82087
82088goog.exportProperty(
82089 ol.style.Stroke.prototype,
82090 'clone',
82091 ol.style.Stroke.prototype.clone);
82092
82093goog.exportProperty(
82094 ol.style.Stroke.prototype,
82095 'getColor',
82096 ol.style.Stroke.prototype.getColor);
82097
82098goog.exportProperty(
82099 ol.style.Stroke.prototype,
82100 'getLineCap',
82101 ol.style.Stroke.prototype.getLineCap);
82102
82103goog.exportProperty(
82104 ol.style.Stroke.prototype,
82105 'getLineDash',
82106 ol.style.Stroke.prototype.getLineDash);
82107
82108goog.exportProperty(
82109 ol.style.Stroke.prototype,
82110 'getLineDashOffset',
82111 ol.style.Stroke.prototype.getLineDashOffset);
82112
82113goog.exportProperty(
82114 ol.style.Stroke.prototype,
82115 'getLineJoin',
82116 ol.style.Stroke.prototype.getLineJoin);
82117
82118goog.exportProperty(
82119 ol.style.Stroke.prototype,
82120 'getMiterLimit',
82121 ol.style.Stroke.prototype.getMiterLimit);
82122
82123goog.exportProperty(
82124 ol.style.Stroke.prototype,
82125 'getWidth',
82126 ol.style.Stroke.prototype.getWidth);
82127
82128goog.exportProperty(
82129 ol.style.Stroke.prototype,
82130 'setColor',
82131 ol.style.Stroke.prototype.setColor);
82132
82133goog.exportProperty(
82134 ol.style.Stroke.prototype,
82135 'setLineCap',
82136 ol.style.Stroke.prototype.setLineCap);
82137
82138goog.exportProperty(
82139 ol.style.Stroke.prototype,
82140 'setLineDash',
82141 ol.style.Stroke.prototype.setLineDash);
82142
82143goog.exportProperty(
82144 ol.style.Stroke.prototype,
82145 'setLineDashOffset',
82146 ol.style.Stroke.prototype.setLineDashOffset);
82147
82148goog.exportProperty(
82149 ol.style.Stroke.prototype,
82150 'setLineJoin',
82151 ol.style.Stroke.prototype.setLineJoin);
82152
82153goog.exportProperty(
82154 ol.style.Stroke.prototype,
82155 'setMiterLimit',
82156 ol.style.Stroke.prototype.setMiterLimit);
82157
82158goog.exportProperty(
82159 ol.style.Stroke.prototype,
82160 'setWidth',
82161 ol.style.Stroke.prototype.setWidth);
82162
82163goog.exportSymbol(
82164 'ol.style.Style',
82165 ol.style.Style,
82166 OPENLAYERS);
82167
82168goog.exportProperty(
82169 ol.style.Style.prototype,
82170 'clone',
82171 ol.style.Style.prototype.clone);
82172
82173goog.exportProperty(
82174 ol.style.Style.prototype,
82175 'getRenderer',
82176 ol.style.Style.prototype.getRenderer);
82177
82178goog.exportProperty(
82179 ol.style.Style.prototype,
82180 'setRenderer',
82181 ol.style.Style.prototype.setRenderer);
82182
82183goog.exportProperty(
82184 ol.style.Style.prototype,
82185 'getGeometry',
82186 ol.style.Style.prototype.getGeometry);
82187
82188goog.exportProperty(
82189 ol.style.Style.prototype,
82190 'getGeometryFunction',
82191 ol.style.Style.prototype.getGeometryFunction);
82192
82193goog.exportProperty(
82194 ol.style.Style.prototype,
82195 'getFill',
82196 ol.style.Style.prototype.getFill);
82197
82198goog.exportProperty(
82199 ol.style.Style.prototype,
82200 'setFill',
82201 ol.style.Style.prototype.setFill);
82202
82203goog.exportProperty(
82204 ol.style.Style.prototype,
82205 'getImage',
82206 ol.style.Style.prototype.getImage);
82207
82208goog.exportProperty(
82209 ol.style.Style.prototype,
82210 'setImage',
82211 ol.style.Style.prototype.setImage);
82212
82213goog.exportProperty(
82214 ol.style.Style.prototype,
82215 'getStroke',
82216 ol.style.Style.prototype.getStroke);
82217
82218goog.exportProperty(
82219 ol.style.Style.prototype,
82220 'setStroke',
82221 ol.style.Style.prototype.setStroke);
82222
82223goog.exportProperty(
82224 ol.style.Style.prototype,
82225 'getText',
82226 ol.style.Style.prototype.getText);
82227
82228goog.exportProperty(
82229 ol.style.Style.prototype,
82230 'setText',
82231 ol.style.Style.prototype.setText);
82232
82233goog.exportProperty(
82234 ol.style.Style.prototype,
82235 'getZIndex',
82236 ol.style.Style.prototype.getZIndex);
82237
82238goog.exportProperty(
82239 ol.style.Style.prototype,
82240 'setGeometry',
82241 ol.style.Style.prototype.setGeometry);
82242
82243goog.exportProperty(
82244 ol.style.Style.prototype,
82245 'setZIndex',
82246 ol.style.Style.prototype.setZIndex);
82247
82248goog.exportSymbol(
82249 'ol.style.Text',
82250 ol.style.Text,
82251 OPENLAYERS);
82252
82253goog.exportProperty(
82254 ol.style.Text.prototype,
82255 'clone',
82256 ol.style.Text.prototype.clone);
82257
82258goog.exportProperty(
82259 ol.style.Text.prototype,
82260 'getFont',
82261 ol.style.Text.prototype.getFont);
82262
82263goog.exportProperty(
82264 ol.style.Text.prototype,
82265 'getOffsetX',
82266 ol.style.Text.prototype.getOffsetX);
82267
82268goog.exportProperty(
82269 ol.style.Text.prototype,
82270 'getOffsetY',
82271 ol.style.Text.prototype.getOffsetY);
82272
82273goog.exportProperty(
82274 ol.style.Text.prototype,
82275 'getFill',
82276 ol.style.Text.prototype.getFill);
82277
82278goog.exportProperty(
82279 ol.style.Text.prototype,
82280 'getRotateWithView',
82281 ol.style.Text.prototype.getRotateWithView);
82282
82283goog.exportProperty(
82284 ol.style.Text.prototype,
82285 'getRotation',
82286 ol.style.Text.prototype.getRotation);
82287
82288goog.exportProperty(
82289 ol.style.Text.prototype,
82290 'getScale',
82291 ol.style.Text.prototype.getScale);
82292
82293goog.exportProperty(
82294 ol.style.Text.prototype,
82295 'getStroke',
82296 ol.style.Text.prototype.getStroke);
82297
82298goog.exportProperty(
82299 ol.style.Text.prototype,
82300 'getText',
82301 ol.style.Text.prototype.getText);
82302
82303goog.exportProperty(
82304 ol.style.Text.prototype,
82305 'getTextAlign',
82306 ol.style.Text.prototype.getTextAlign);
82307
82308goog.exportProperty(
82309 ol.style.Text.prototype,
82310 'getTextBaseline',
82311 ol.style.Text.prototype.getTextBaseline);
82312
82313goog.exportProperty(
82314 ol.style.Text.prototype,
82315 'setFont',
82316 ol.style.Text.prototype.setFont);
82317
82318goog.exportProperty(
82319 ol.style.Text.prototype,
82320 'setOffsetX',
82321 ol.style.Text.prototype.setOffsetX);
82322
82323goog.exportProperty(
82324 ol.style.Text.prototype,
82325 'setOffsetY',
82326 ol.style.Text.prototype.setOffsetY);
82327
82328goog.exportProperty(
82329 ol.style.Text.prototype,
82330 'setFill',
82331 ol.style.Text.prototype.setFill);
82332
82333goog.exportProperty(
82334 ol.style.Text.prototype,
82335 'setRotation',
82336 ol.style.Text.prototype.setRotation);
82337
82338goog.exportProperty(
82339 ol.style.Text.prototype,
82340 'setScale',
82341 ol.style.Text.prototype.setScale);
82342
82343goog.exportProperty(
82344 ol.style.Text.prototype,
82345 'setStroke',
82346 ol.style.Text.prototype.setStroke);
82347
82348goog.exportProperty(
82349 ol.style.Text.prototype,
82350 'setText',
82351 ol.style.Text.prototype.setText);
82352
82353goog.exportProperty(
82354 ol.style.Text.prototype,
82355 'setTextAlign',
82356 ol.style.Text.prototype.setTextAlign);
82357
82358goog.exportProperty(
82359 ol.style.Text.prototype,
82360 'setTextBaseline',
82361 ol.style.Text.prototype.setTextBaseline);
82362
82363goog.exportSymbol(
82364 'ol.source.BingMaps',
82365 ol.source.BingMaps,
82366 OPENLAYERS);
82367
82368goog.exportSymbol(
82369 'ol.source.BingMaps.TOS_ATTRIBUTION',
82370 ol.source.BingMaps.TOS_ATTRIBUTION,
82371 OPENLAYERS);
82372
82373goog.exportProperty(
82374 ol.source.BingMaps.prototype,
82375 'getApiKey',
82376 ol.source.BingMaps.prototype.getApiKey);
82377
82378goog.exportProperty(
82379 ol.source.BingMaps.prototype,
82380 'getImagerySet',
82381 ol.source.BingMaps.prototype.getImagerySet);
82382
82383goog.exportSymbol(
82384 'ol.source.CartoDB',
82385 ol.source.CartoDB,
82386 OPENLAYERS);
82387
82388goog.exportProperty(
82389 ol.source.CartoDB.prototype,
82390 'getConfig',
82391 ol.source.CartoDB.prototype.getConfig);
82392
82393goog.exportProperty(
82394 ol.source.CartoDB.prototype,
82395 'updateConfig',
82396 ol.source.CartoDB.prototype.updateConfig);
82397
82398goog.exportProperty(
82399 ol.source.CartoDB.prototype,
82400 'setConfig',
82401 ol.source.CartoDB.prototype.setConfig);
82402
82403goog.exportSymbol(
82404 'ol.source.Cluster',
82405 ol.source.Cluster,
82406 OPENLAYERS);
82407
82408goog.exportProperty(
82409 ol.source.Cluster.prototype,
82410 'getDistance',
82411 ol.source.Cluster.prototype.getDistance);
82412
82413goog.exportProperty(
82414 ol.source.Cluster.prototype,
82415 'getSource',
82416 ol.source.Cluster.prototype.getSource);
82417
82418goog.exportProperty(
82419 ol.source.Cluster.prototype,
82420 'setDistance',
82421 ol.source.Cluster.prototype.setDistance);
82422
82423goog.exportSymbol(
82424 'ol.source.Image',
82425 ol.source.Image,
82426 OPENLAYERS);
82427
82428goog.exportProperty(
82429 ol.source.Image.Event.prototype,
82430 'image',
82431 ol.source.Image.Event.prototype.image);
82432
82433goog.exportSymbol(
82434 'ol.source.ImageArcGISRest',
82435 ol.source.ImageArcGISRest,
82436 OPENLAYERS);
82437
82438goog.exportProperty(
82439 ol.source.ImageArcGISRest.prototype,
82440 'getParams',
82441 ol.source.ImageArcGISRest.prototype.getParams);
82442
82443goog.exportProperty(
82444 ol.source.ImageArcGISRest.prototype,
82445 'getImageLoadFunction',
82446 ol.source.ImageArcGISRest.prototype.getImageLoadFunction);
82447
82448goog.exportProperty(
82449 ol.source.ImageArcGISRest.prototype,
82450 'getUrl',
82451 ol.source.ImageArcGISRest.prototype.getUrl);
82452
82453goog.exportProperty(
82454 ol.source.ImageArcGISRest.prototype,
82455 'setImageLoadFunction',
82456 ol.source.ImageArcGISRest.prototype.setImageLoadFunction);
82457
82458goog.exportProperty(
82459 ol.source.ImageArcGISRest.prototype,
82460 'setUrl',
82461 ol.source.ImageArcGISRest.prototype.setUrl);
82462
82463goog.exportProperty(
82464 ol.source.ImageArcGISRest.prototype,
82465 'updateParams',
82466 ol.source.ImageArcGISRest.prototype.updateParams);
82467
82468goog.exportSymbol(
82469 'ol.source.ImageCanvas',
82470 ol.source.ImageCanvas,
82471 OPENLAYERS);
82472
82473goog.exportSymbol(
82474 'ol.source.ImageMapGuide',
82475 ol.source.ImageMapGuide,
82476 OPENLAYERS);
82477
82478goog.exportProperty(
82479 ol.source.ImageMapGuide.prototype,
82480 'getParams',
82481 ol.source.ImageMapGuide.prototype.getParams);
82482
82483goog.exportProperty(
82484 ol.source.ImageMapGuide.prototype,
82485 'getImageLoadFunction',
82486 ol.source.ImageMapGuide.prototype.getImageLoadFunction);
82487
82488goog.exportProperty(
82489 ol.source.ImageMapGuide.prototype,
82490 'updateParams',
82491 ol.source.ImageMapGuide.prototype.updateParams);
82492
82493goog.exportProperty(
82494 ol.source.ImageMapGuide.prototype,
82495 'setImageLoadFunction',
82496 ol.source.ImageMapGuide.prototype.setImageLoadFunction);
82497
82498goog.exportSymbol(
82499 'ol.source.ImageStatic',
82500 ol.source.ImageStatic,
82501 OPENLAYERS);
82502
82503goog.exportSymbol(
82504 'ol.source.ImageVector',
82505 ol.source.ImageVector,
82506 OPENLAYERS);
82507
82508goog.exportProperty(
82509 ol.source.ImageVector.prototype,
82510 'getSource',
82511 ol.source.ImageVector.prototype.getSource);
82512
82513goog.exportProperty(
82514 ol.source.ImageVector.prototype,
82515 'getStyle',
82516 ol.source.ImageVector.prototype.getStyle);
82517
82518goog.exportProperty(
82519 ol.source.ImageVector.prototype,
82520 'getStyleFunction',
82521 ol.source.ImageVector.prototype.getStyleFunction);
82522
82523goog.exportProperty(
82524 ol.source.ImageVector.prototype,
82525 'setStyle',
82526 ol.source.ImageVector.prototype.setStyle);
82527
82528goog.exportSymbol(
82529 'ol.source.ImageWMS',
82530 ol.source.ImageWMS,
82531 OPENLAYERS);
82532
82533goog.exportProperty(
82534 ol.source.ImageWMS.prototype,
82535 'getGetFeatureInfoUrl',
82536 ol.source.ImageWMS.prototype.getGetFeatureInfoUrl);
82537
82538goog.exportProperty(
82539 ol.source.ImageWMS.prototype,
82540 'getParams',
82541 ol.source.ImageWMS.prototype.getParams);
82542
82543goog.exportProperty(
82544 ol.source.ImageWMS.prototype,
82545 'getImageLoadFunction',
82546 ol.source.ImageWMS.prototype.getImageLoadFunction);
82547
82548goog.exportProperty(
82549 ol.source.ImageWMS.prototype,
82550 'getUrl',
82551 ol.source.ImageWMS.prototype.getUrl);
82552
82553goog.exportProperty(
82554 ol.source.ImageWMS.prototype,
82555 'setImageLoadFunction',
82556 ol.source.ImageWMS.prototype.setImageLoadFunction);
82557
82558goog.exportProperty(
82559 ol.source.ImageWMS.prototype,
82560 'setUrl',
82561 ol.source.ImageWMS.prototype.setUrl);
82562
82563goog.exportProperty(
82564 ol.source.ImageWMS.prototype,
82565 'updateParams',
82566 ol.source.ImageWMS.prototype.updateParams);
82567
82568goog.exportSymbol(
82569 'ol.source.OSM',
82570 ol.source.OSM,
82571 OPENLAYERS);
82572
82573goog.exportSymbol(
82574 'ol.source.OSM.ATTRIBUTION',
82575 ol.source.OSM.ATTRIBUTION,
82576 OPENLAYERS);
82577
82578goog.exportSymbol(
82579 'ol.source.Raster',
82580 ol.source.Raster,
82581 OPENLAYERS);
82582
82583goog.exportProperty(
82584 ol.source.Raster.prototype,
82585 'setOperation',
82586 ol.source.Raster.prototype.setOperation);
82587
82588goog.exportProperty(
82589 ol.source.Raster.Event.prototype,
82590 'extent',
82591 ol.source.Raster.Event.prototype.extent);
82592
82593goog.exportProperty(
82594 ol.source.Raster.Event.prototype,
82595 'resolution',
82596 ol.source.Raster.Event.prototype.resolution);
82597
82598goog.exportProperty(
82599 ol.source.Raster.Event.prototype,
82600 'data',
82601 ol.source.Raster.Event.prototype.data);
82602
82603goog.exportSymbol(
82604 'ol.source.Source',
82605 ol.source.Source,
82606 OPENLAYERS);
82607
82608goog.exportProperty(
82609 ol.source.Source.prototype,
82610 'getAttributions',
82611 ol.source.Source.prototype.getAttributions);
82612
82613goog.exportProperty(
82614 ol.source.Source.prototype,
82615 'getLogo',
82616 ol.source.Source.prototype.getLogo);
82617
82618goog.exportProperty(
82619 ol.source.Source.prototype,
82620 'getProjection',
82621 ol.source.Source.prototype.getProjection);
82622
82623goog.exportProperty(
82624 ol.source.Source.prototype,
82625 'getState',
82626 ol.source.Source.prototype.getState);
82627
82628goog.exportProperty(
82629 ol.source.Source.prototype,
82630 'refresh',
82631 ol.source.Source.prototype.refresh);
82632
82633goog.exportProperty(
82634 ol.source.Source.prototype,
82635 'setAttributions',
82636 ol.source.Source.prototype.setAttributions);
82637
82638goog.exportSymbol(
82639 'ol.source.Stamen',
82640 ol.source.Stamen,
82641 OPENLAYERS);
82642
82643goog.exportSymbol(
82644 'ol.source.Tile',
82645 ol.source.Tile,
82646 OPENLAYERS);
82647
82648goog.exportProperty(
82649 ol.source.Tile.prototype,
82650 'getTileGrid',
82651 ol.source.Tile.prototype.getTileGrid);
82652
82653goog.exportProperty(
82654 ol.source.Tile.Event.prototype,
82655 'tile',
82656 ol.source.Tile.Event.prototype.tile);
82657
82658goog.exportSymbol(
82659 'ol.source.TileArcGISRest',
82660 ol.source.TileArcGISRest,
82661 OPENLAYERS);
82662
82663goog.exportProperty(
82664 ol.source.TileArcGISRest.prototype,
82665 'getParams',
82666 ol.source.TileArcGISRest.prototype.getParams);
82667
82668goog.exportProperty(
82669 ol.source.TileArcGISRest.prototype,
82670 'updateParams',
82671 ol.source.TileArcGISRest.prototype.updateParams);
82672
82673goog.exportSymbol(
82674 'ol.source.TileDebug',
82675 ol.source.TileDebug,
82676 OPENLAYERS);
82677
82678goog.exportSymbol(
82679 'ol.source.TileImage',
82680 ol.source.TileImage,
82681 OPENLAYERS);
82682
82683goog.exportProperty(
82684 ol.source.TileImage.prototype,
82685 'setRenderReprojectionEdges',
82686 ol.source.TileImage.prototype.setRenderReprojectionEdges);
82687
82688goog.exportProperty(
82689 ol.source.TileImage.prototype,
82690 'setTileGridForProjection',
82691 ol.source.TileImage.prototype.setTileGridForProjection);
82692
82693goog.exportSymbol(
82694 'ol.source.TileJSON',
82695 ol.source.TileJSON,
82696 OPENLAYERS);
82697
82698goog.exportProperty(
82699 ol.source.TileJSON.prototype,
82700 'getTileJSON',
82701 ol.source.TileJSON.prototype.getTileJSON);
82702
82703goog.exportSymbol(
82704 'ol.source.TileUTFGrid',
82705 ol.source.TileUTFGrid,
82706 OPENLAYERS);
82707
82708goog.exportProperty(
82709 ol.source.TileUTFGrid.prototype,
82710 'getTemplate',
82711 ol.source.TileUTFGrid.prototype.getTemplate);
82712
82713goog.exportProperty(
82714 ol.source.TileUTFGrid.prototype,
82715 'forDataAtCoordinateAndResolution',
82716 ol.source.TileUTFGrid.prototype.forDataAtCoordinateAndResolution);
82717
82718goog.exportSymbol(
82719 'ol.source.TileWMS',
82720 ol.source.TileWMS,
82721 OPENLAYERS);
82722
82723goog.exportProperty(
82724 ol.source.TileWMS.prototype,
82725 'getGetFeatureInfoUrl',
82726 ol.source.TileWMS.prototype.getGetFeatureInfoUrl);
82727
82728goog.exportProperty(
82729 ol.source.TileWMS.prototype,
82730 'getParams',
82731 ol.source.TileWMS.prototype.getParams);
82732
82733goog.exportProperty(
82734 ol.source.TileWMS.prototype,
82735 'updateParams',
82736 ol.source.TileWMS.prototype.updateParams);
82737
82738goog.exportProperty(
82739 ol.source.UrlTile.prototype,
82740 'getTileLoadFunction',
82741 ol.source.UrlTile.prototype.getTileLoadFunction);
82742
82743goog.exportProperty(
82744 ol.source.UrlTile.prototype,
82745 'getTileUrlFunction',
82746 ol.source.UrlTile.prototype.getTileUrlFunction);
82747
82748goog.exportProperty(
82749 ol.source.UrlTile.prototype,
82750 'getUrls',
82751 ol.source.UrlTile.prototype.getUrls);
82752
82753goog.exportProperty(
82754 ol.source.UrlTile.prototype,
82755 'setTileLoadFunction',
82756 ol.source.UrlTile.prototype.setTileLoadFunction);
82757
82758goog.exportProperty(
82759 ol.source.UrlTile.prototype,
82760 'setTileUrlFunction',
82761 ol.source.UrlTile.prototype.setTileUrlFunction);
82762
82763goog.exportProperty(
82764 ol.source.UrlTile.prototype,
82765 'setUrl',
82766 ol.source.UrlTile.prototype.setUrl);
82767
82768goog.exportProperty(
82769 ol.source.UrlTile.prototype,
82770 'setUrls',
82771 ol.source.UrlTile.prototype.setUrls);
82772
82773goog.exportSymbol(
82774 'ol.source.Vector',
82775 ol.source.Vector,
82776 OPENLAYERS);
82777
82778goog.exportProperty(
82779 ol.source.Vector.prototype,
82780 'addFeature',
82781 ol.source.Vector.prototype.addFeature);
82782
82783goog.exportProperty(
82784 ol.source.Vector.prototype,
82785 'addFeatures',
82786 ol.source.Vector.prototype.addFeatures);
82787
82788goog.exportProperty(
82789 ol.source.Vector.prototype,
82790 'clear',
82791 ol.source.Vector.prototype.clear);
82792
82793goog.exportProperty(
82794 ol.source.Vector.prototype,
82795 'forEachFeature',
82796 ol.source.Vector.prototype.forEachFeature);
82797
82798goog.exportProperty(
82799 ol.source.Vector.prototype,
82800 'forEachFeatureInExtent',
82801 ol.source.Vector.prototype.forEachFeatureInExtent);
82802
82803goog.exportProperty(
82804 ol.source.Vector.prototype,
82805 'forEachFeatureIntersectingExtent',
82806 ol.source.Vector.prototype.forEachFeatureIntersectingExtent);
82807
82808goog.exportProperty(
82809 ol.source.Vector.prototype,
82810 'getFeaturesCollection',
82811 ol.source.Vector.prototype.getFeaturesCollection);
82812
82813goog.exportProperty(
82814 ol.source.Vector.prototype,
82815 'getFeatures',
82816 ol.source.Vector.prototype.getFeatures);
82817
82818goog.exportProperty(
82819 ol.source.Vector.prototype,
82820 'getFeaturesAtCoordinate',
82821 ol.source.Vector.prototype.getFeaturesAtCoordinate);
82822
82823goog.exportProperty(
82824 ol.source.Vector.prototype,
82825 'getFeaturesInExtent',
82826 ol.source.Vector.prototype.getFeaturesInExtent);
82827
82828goog.exportProperty(
82829 ol.source.Vector.prototype,
82830 'getClosestFeatureToCoordinate',
82831 ol.source.Vector.prototype.getClosestFeatureToCoordinate);
82832
82833goog.exportProperty(
82834 ol.source.Vector.prototype,
82835 'getExtent',
82836 ol.source.Vector.prototype.getExtent);
82837
82838goog.exportProperty(
82839 ol.source.Vector.prototype,
82840 'getFeatureById',
82841 ol.source.Vector.prototype.getFeatureById);
82842
82843goog.exportProperty(
82844 ol.source.Vector.prototype,
82845 'getFormat',
82846 ol.source.Vector.prototype.getFormat);
82847
82848goog.exportProperty(
82849 ol.source.Vector.prototype,
82850 'getUrl',
82851 ol.source.Vector.prototype.getUrl);
82852
82853goog.exportProperty(
82854 ol.source.Vector.prototype,
82855 'removeFeature',
82856 ol.source.Vector.prototype.removeFeature);
82857
82858goog.exportProperty(
82859 ol.source.Vector.Event.prototype,
82860 'feature',
82861 ol.source.Vector.Event.prototype.feature);
82862
82863goog.exportSymbol(
82864 'ol.source.VectorTile',
82865 ol.source.VectorTile,
82866 OPENLAYERS);
82867
82868goog.exportSymbol(
82869 'ol.source.WMTS',
82870 ol.source.WMTS,
82871 OPENLAYERS);
82872
82873goog.exportProperty(
82874 ol.source.WMTS.prototype,
82875 'getDimensions',
82876 ol.source.WMTS.prototype.getDimensions);
82877
82878goog.exportProperty(
82879 ol.source.WMTS.prototype,
82880 'getFormat',
82881 ol.source.WMTS.prototype.getFormat);
82882
82883goog.exportProperty(
82884 ol.source.WMTS.prototype,
82885 'getLayer',
82886 ol.source.WMTS.prototype.getLayer);
82887
82888goog.exportProperty(
82889 ol.source.WMTS.prototype,
82890 'getMatrixSet',
82891 ol.source.WMTS.prototype.getMatrixSet);
82892
82893goog.exportProperty(
82894 ol.source.WMTS.prototype,
82895 'getRequestEncoding',
82896 ol.source.WMTS.prototype.getRequestEncoding);
82897
82898goog.exportProperty(
82899 ol.source.WMTS.prototype,
82900 'getStyle',
82901 ol.source.WMTS.prototype.getStyle);
82902
82903goog.exportProperty(
82904 ol.source.WMTS.prototype,
82905 'getVersion',
82906 ol.source.WMTS.prototype.getVersion);
82907
82908goog.exportProperty(
82909 ol.source.WMTS.prototype,
82910 'updateDimensions',
82911 ol.source.WMTS.prototype.updateDimensions);
82912
82913goog.exportSymbol(
82914 'ol.source.WMTS.optionsFromCapabilities',
82915 ol.source.WMTS.optionsFromCapabilities,
82916 OPENLAYERS);
82917
82918goog.exportSymbol(
82919 'ol.source.XYZ',
82920 ol.source.XYZ,
82921 OPENLAYERS);
82922
82923goog.exportSymbol(
82924 'ol.source.Zoomify',
82925 ol.source.Zoomify,
82926 OPENLAYERS);
82927
82928goog.exportProperty(
82929 ol.render.Event.prototype,
82930 'vectorContext',
82931 ol.render.Event.prototype.vectorContext);
82932
82933goog.exportProperty(
82934 ol.render.Event.prototype,
82935 'frameState',
82936 ol.render.Event.prototype.frameState);
82937
82938goog.exportProperty(
82939 ol.render.Event.prototype,
82940 'context',
82941 ol.render.Event.prototype.context);
82942
82943goog.exportProperty(
82944 ol.render.Event.prototype,
82945 'glContext',
82946 ol.render.Event.prototype.glContext);
82947
82948goog.exportProperty(
82949 ol.render.Feature.prototype,
82950 'get',
82951 ol.render.Feature.prototype.get);
82952
82953goog.exportProperty(
82954 ol.render.Feature.prototype,
82955 'getExtent',
82956 ol.render.Feature.prototype.getExtent);
82957
82958goog.exportProperty(
82959 ol.render.Feature.prototype,
82960 'getId',
82961 ol.render.Feature.prototype.getId);
82962
82963goog.exportProperty(
82964 ol.render.Feature.prototype,
82965 'getGeometry',
82966 ol.render.Feature.prototype.getGeometry);
82967
82968goog.exportProperty(
82969 ol.render.Feature.prototype,
82970 'getProperties',
82971 ol.render.Feature.prototype.getProperties);
82972
82973goog.exportProperty(
82974 ol.render.Feature.prototype,
82975 'getType',
82976 ol.render.Feature.prototype.getType);
82977
82978goog.exportSymbol(
82979 'ol.render.VectorContext',
82980 ol.render.VectorContext,
82981 OPENLAYERS);
82982
82983goog.exportProperty(
82984 ol.render.webgl.Immediate.prototype,
82985 'setStyle',
82986 ol.render.webgl.Immediate.prototype.setStyle);
82987
82988goog.exportProperty(
82989 ol.render.webgl.Immediate.prototype,
82990 'drawGeometry',
82991 ol.render.webgl.Immediate.prototype.drawGeometry);
82992
82993goog.exportProperty(
82994 ol.render.webgl.Immediate.prototype,
82995 'drawFeature',
82996 ol.render.webgl.Immediate.prototype.drawFeature);
82997
82998goog.exportProperty(
82999 ol.render.canvas.Immediate.prototype,
83000 'drawCircle',
83001 ol.render.canvas.Immediate.prototype.drawCircle);
83002
83003goog.exportProperty(
83004 ol.render.canvas.Immediate.prototype,
83005 'setStyle',
83006 ol.render.canvas.Immediate.prototype.setStyle);
83007
83008goog.exportProperty(
83009 ol.render.canvas.Immediate.prototype,
83010 'drawGeometry',
83011 ol.render.canvas.Immediate.prototype.drawGeometry);
83012
83013goog.exportProperty(
83014 ol.render.canvas.Immediate.prototype,
83015 'drawFeature',
83016 ol.render.canvas.Immediate.prototype.drawFeature);
83017
83018goog.exportSymbol(
83019 'ol.proj.common.add',
83020 ol.proj.common.add,
83021 OPENLAYERS);
83022
83023goog.exportSymbol(
83024 'ol.proj.Projection',
83025 ol.proj.Projection,
83026 OPENLAYERS);
83027
83028goog.exportProperty(
83029 ol.proj.Projection.prototype,
83030 'getCode',
83031 ol.proj.Projection.prototype.getCode);
83032
83033goog.exportProperty(
83034 ol.proj.Projection.prototype,
83035 'getExtent',
83036 ol.proj.Projection.prototype.getExtent);
83037
83038goog.exportProperty(
83039 ol.proj.Projection.prototype,
83040 'getUnits',
83041 ol.proj.Projection.prototype.getUnits);
83042
83043goog.exportProperty(
83044 ol.proj.Projection.prototype,
83045 'getMetersPerUnit',
83046 ol.proj.Projection.prototype.getMetersPerUnit);
83047
83048goog.exportProperty(
83049 ol.proj.Projection.prototype,
83050 'getWorldExtent',
83051 ol.proj.Projection.prototype.getWorldExtent);
83052
83053goog.exportProperty(
83054 ol.proj.Projection.prototype,
83055 'isGlobal',
83056 ol.proj.Projection.prototype.isGlobal);
83057
83058goog.exportProperty(
83059 ol.proj.Projection.prototype,
83060 'setGlobal',
83061 ol.proj.Projection.prototype.setGlobal);
83062
83063goog.exportProperty(
83064 ol.proj.Projection.prototype,
83065 'setExtent',
83066 ol.proj.Projection.prototype.setExtent);
83067
83068goog.exportProperty(
83069 ol.proj.Projection.prototype,
83070 'setWorldExtent',
83071 ol.proj.Projection.prototype.setWorldExtent);
83072
83073goog.exportProperty(
83074 ol.proj.Projection.prototype,
83075 'setGetPointResolution',
83076 ol.proj.Projection.prototype.setGetPointResolution);
83077
83078goog.exportSymbol(
83079 'ol.proj.Units.METERS_PER_UNIT',
83080 ol.proj.Units.METERS_PER_UNIT,
83081 OPENLAYERS);
83082
83083goog.exportSymbol(
83084 'ol.layer.Base',
83085 ol.layer.Base,
83086 OPENLAYERS);
83087
83088goog.exportProperty(
83089 ol.layer.Base.prototype,
83090 'getExtent',
83091 ol.layer.Base.prototype.getExtent);
83092
83093goog.exportProperty(
83094 ol.layer.Base.prototype,
83095 'getMaxResolution',
83096 ol.layer.Base.prototype.getMaxResolution);
83097
83098goog.exportProperty(
83099 ol.layer.Base.prototype,
83100 'getMinResolution',
83101 ol.layer.Base.prototype.getMinResolution);
83102
83103goog.exportProperty(
83104 ol.layer.Base.prototype,
83105 'getOpacity',
83106 ol.layer.Base.prototype.getOpacity);
83107
83108goog.exportProperty(
83109 ol.layer.Base.prototype,
83110 'getVisible',
83111 ol.layer.Base.prototype.getVisible);
83112
83113goog.exportProperty(
83114 ol.layer.Base.prototype,
83115 'getZIndex',
83116 ol.layer.Base.prototype.getZIndex);
83117
83118goog.exportProperty(
83119 ol.layer.Base.prototype,
83120 'setExtent',
83121 ol.layer.Base.prototype.setExtent);
83122
83123goog.exportProperty(
83124 ol.layer.Base.prototype,
83125 'setMaxResolution',
83126 ol.layer.Base.prototype.setMaxResolution);
83127
83128goog.exportProperty(
83129 ol.layer.Base.prototype,
83130 'setMinResolution',
83131 ol.layer.Base.prototype.setMinResolution);
83132
83133goog.exportProperty(
83134 ol.layer.Base.prototype,
83135 'setOpacity',
83136 ol.layer.Base.prototype.setOpacity);
83137
83138goog.exportProperty(
83139 ol.layer.Base.prototype,
83140 'setVisible',
83141 ol.layer.Base.prototype.setVisible);
83142
83143goog.exportProperty(
83144 ol.layer.Base.prototype,
83145 'setZIndex',
83146 ol.layer.Base.prototype.setZIndex);
83147
83148goog.exportSymbol(
83149 'ol.layer.Group',
83150 ol.layer.Group,
83151 OPENLAYERS);
83152
83153goog.exportProperty(
83154 ol.layer.Group.prototype,
83155 'getLayers',
83156 ol.layer.Group.prototype.getLayers);
83157
83158goog.exportProperty(
83159 ol.layer.Group.prototype,
83160 'setLayers',
83161 ol.layer.Group.prototype.setLayers);
83162
83163goog.exportSymbol(
83164 'ol.layer.Heatmap',
83165 ol.layer.Heatmap,
83166 OPENLAYERS);
83167
83168goog.exportProperty(
83169 ol.layer.Heatmap.prototype,
83170 'getBlur',
83171 ol.layer.Heatmap.prototype.getBlur);
83172
83173goog.exportProperty(
83174 ol.layer.Heatmap.prototype,
83175 'getGradient',
83176 ol.layer.Heatmap.prototype.getGradient);
83177
83178goog.exportProperty(
83179 ol.layer.Heatmap.prototype,
83180 'getRadius',
83181 ol.layer.Heatmap.prototype.getRadius);
83182
83183goog.exportProperty(
83184 ol.layer.Heatmap.prototype,
83185 'setBlur',
83186 ol.layer.Heatmap.prototype.setBlur);
83187
83188goog.exportProperty(
83189 ol.layer.Heatmap.prototype,
83190 'setGradient',
83191 ol.layer.Heatmap.prototype.setGradient);
83192
83193goog.exportProperty(
83194 ol.layer.Heatmap.prototype,
83195 'setRadius',
83196 ol.layer.Heatmap.prototype.setRadius);
83197
83198goog.exportSymbol(
83199 'ol.layer.Image',
83200 ol.layer.Image,
83201 OPENLAYERS);
83202
83203goog.exportProperty(
83204 ol.layer.Image.prototype,
83205 'getSource',
83206 ol.layer.Image.prototype.getSource);
83207
83208goog.exportSymbol(
83209 'ol.layer.Layer',
83210 ol.layer.Layer,
83211 OPENLAYERS);
83212
83213goog.exportProperty(
83214 ol.layer.Layer.prototype,
83215 'getSource',
83216 ol.layer.Layer.prototype.getSource);
83217
83218goog.exportProperty(
83219 ol.layer.Layer.prototype,
83220 'setMap',
83221 ol.layer.Layer.prototype.setMap);
83222
83223goog.exportProperty(
83224 ol.layer.Layer.prototype,
83225 'setSource',
83226 ol.layer.Layer.prototype.setSource);
83227
83228goog.exportSymbol(
83229 'ol.layer.Tile',
83230 ol.layer.Tile,
83231 OPENLAYERS);
83232
83233goog.exportProperty(
83234 ol.layer.Tile.prototype,
83235 'getPreload',
83236 ol.layer.Tile.prototype.getPreload);
83237
83238goog.exportProperty(
83239 ol.layer.Tile.prototype,
83240 'getSource',
83241 ol.layer.Tile.prototype.getSource);
83242
83243goog.exportProperty(
83244 ol.layer.Tile.prototype,
83245 'setPreload',
83246 ol.layer.Tile.prototype.setPreload);
83247
83248goog.exportProperty(
83249 ol.layer.Tile.prototype,
83250 'getUseInterimTilesOnError',
83251 ol.layer.Tile.prototype.getUseInterimTilesOnError);
83252
83253goog.exportProperty(
83254 ol.layer.Tile.prototype,
83255 'setUseInterimTilesOnError',
83256 ol.layer.Tile.prototype.setUseInterimTilesOnError);
83257
83258goog.exportSymbol(
83259 'ol.layer.Vector',
83260 ol.layer.Vector,
83261 OPENLAYERS);
83262
83263goog.exportProperty(
83264 ol.layer.Vector.prototype,
83265 'getSource',
83266 ol.layer.Vector.prototype.getSource);
83267
83268goog.exportProperty(
83269 ol.layer.Vector.prototype,
83270 'getStyle',
83271 ol.layer.Vector.prototype.getStyle);
83272
83273goog.exportProperty(
83274 ol.layer.Vector.prototype,
83275 'getStyleFunction',
83276 ol.layer.Vector.prototype.getStyleFunction);
83277
83278goog.exportProperty(
83279 ol.layer.Vector.prototype,
83280 'setStyle',
83281 ol.layer.Vector.prototype.setStyle);
83282
83283goog.exportSymbol(
83284 'ol.layer.VectorTile',
83285 ol.layer.VectorTile,
83286 OPENLAYERS);
83287
83288goog.exportProperty(
83289 ol.layer.VectorTile.prototype,
83290 'getPreload',
83291 ol.layer.VectorTile.prototype.getPreload);
83292
83293goog.exportProperty(
83294 ol.layer.VectorTile.prototype,
83295 'getUseInterimTilesOnError',
83296 ol.layer.VectorTile.prototype.getUseInterimTilesOnError);
83297
83298goog.exportProperty(
83299 ol.layer.VectorTile.prototype,
83300 'setPreload',
83301 ol.layer.VectorTile.prototype.setPreload);
83302
83303goog.exportProperty(
83304 ol.layer.VectorTile.prototype,
83305 'setUseInterimTilesOnError',
83306 ol.layer.VectorTile.prototype.setUseInterimTilesOnError);
83307
83308goog.exportProperty(
83309 ol.layer.VectorTile.prototype,
83310 'getSource',
83311 ol.layer.VectorTile.prototype.getSource);
83312
83313goog.exportSymbol(
83314 'ol.interaction.DoubleClickZoom',
83315 ol.interaction.DoubleClickZoom,
83316 OPENLAYERS);
83317
83318goog.exportSymbol(
83319 'ol.interaction.DoubleClickZoom.handleEvent',
83320 ol.interaction.DoubleClickZoom.handleEvent,
83321 OPENLAYERS);
83322
83323goog.exportSymbol(
83324 'ol.interaction.DragAndDrop',
83325 ol.interaction.DragAndDrop,
83326 OPENLAYERS);
83327
83328goog.exportSymbol(
83329 'ol.interaction.DragAndDrop.handleEvent',
83330 ol.interaction.DragAndDrop.handleEvent,
83331 OPENLAYERS);
83332
83333goog.exportProperty(
83334 ol.interaction.DragAndDrop.Event.prototype,
83335 'features',
83336 ol.interaction.DragAndDrop.Event.prototype.features);
83337
83338goog.exportProperty(
83339 ol.interaction.DragAndDrop.Event.prototype,
83340 'file',
83341 ol.interaction.DragAndDrop.Event.prototype.file);
83342
83343goog.exportProperty(
83344 ol.interaction.DragAndDrop.Event.prototype,
83345 'projection',
83346 ol.interaction.DragAndDrop.Event.prototype.projection);
83347
83348goog.exportSymbol(
83349 'ol.interaction.DragBox',
83350 ol.interaction.DragBox,
83351 OPENLAYERS);
83352
83353goog.exportProperty(
83354 ol.interaction.DragBox.prototype,
83355 'getGeometry',
83356 ol.interaction.DragBox.prototype.getGeometry);
83357
83358goog.exportProperty(
83359 ol.interaction.DragBox.Event.prototype,
83360 'coordinate',
83361 ol.interaction.DragBox.Event.prototype.coordinate);
83362
83363goog.exportProperty(
83364 ol.interaction.DragBox.Event.prototype,
83365 'mapBrowserEvent',
83366 ol.interaction.DragBox.Event.prototype.mapBrowserEvent);
83367
83368goog.exportSymbol(
83369 'ol.interaction.DragPan',
83370 ol.interaction.DragPan,
83371 OPENLAYERS);
83372
83373goog.exportSymbol(
83374 'ol.interaction.DragRotate',
83375 ol.interaction.DragRotate,
83376 OPENLAYERS);
83377
83378goog.exportSymbol(
83379 'ol.interaction.DragRotateAndZoom',
83380 ol.interaction.DragRotateAndZoom,
83381 OPENLAYERS);
83382
83383goog.exportSymbol(
83384 'ol.interaction.DragZoom',
83385 ol.interaction.DragZoom,
83386 OPENLAYERS);
83387
83388goog.exportSymbol(
83389 'ol.interaction.Draw',
83390 ol.interaction.Draw,
83391 OPENLAYERS);
83392
83393goog.exportSymbol(
83394 'ol.interaction.Draw.handleEvent',
83395 ol.interaction.Draw.handleEvent,
83396 OPENLAYERS);
83397
83398goog.exportProperty(
83399 ol.interaction.Draw.prototype,
83400 'removeLastPoint',
83401 ol.interaction.Draw.prototype.removeLastPoint);
83402
83403goog.exportProperty(
83404 ol.interaction.Draw.prototype,
83405 'finishDrawing',
83406 ol.interaction.Draw.prototype.finishDrawing);
83407
83408goog.exportProperty(
83409 ol.interaction.Draw.prototype,
83410 'extend',
83411 ol.interaction.Draw.prototype.extend);
83412
83413goog.exportSymbol(
83414 'ol.interaction.Draw.createRegularPolygon',
83415 ol.interaction.Draw.createRegularPolygon,
83416 OPENLAYERS);
83417
83418goog.exportSymbol(
83419 'ol.interaction.Draw.createBox',
83420 ol.interaction.Draw.createBox,
83421 OPENLAYERS);
83422
83423goog.exportProperty(
83424 ol.interaction.Draw.Event.prototype,
83425 'feature',
83426 ol.interaction.Draw.Event.prototype.feature);
83427
83428goog.exportSymbol(
83429 'ol.interaction.Extent',
83430 ol.interaction.Extent,
83431 OPENLAYERS);
83432
83433goog.exportProperty(
83434 ol.interaction.Extent.prototype,
83435 'getExtent',
83436 ol.interaction.Extent.prototype.getExtent);
83437
83438goog.exportProperty(
83439 ol.interaction.Extent.prototype,
83440 'setExtent',
83441 ol.interaction.Extent.prototype.setExtent);
83442
83443goog.exportProperty(
83444 ol.interaction.Extent.Event.prototype,
83445 'extent',
83446 ol.interaction.Extent.Event.prototype.extent);
83447
83448goog.exportSymbol(
83449 'ol.interaction.Interaction',
83450 ol.interaction.Interaction,
83451 OPENLAYERS);
83452
83453goog.exportProperty(
83454 ol.interaction.Interaction.prototype,
83455 'getActive',
83456 ol.interaction.Interaction.prototype.getActive);
83457
83458goog.exportProperty(
83459 ol.interaction.Interaction.prototype,
83460 'getMap',
83461 ol.interaction.Interaction.prototype.getMap);
83462
83463goog.exportProperty(
83464 ol.interaction.Interaction.prototype,
83465 'setActive',
83466 ol.interaction.Interaction.prototype.setActive);
83467
83468goog.exportSymbol(
83469 'ol.interaction.KeyboardPan',
83470 ol.interaction.KeyboardPan,
83471 OPENLAYERS);
83472
83473goog.exportSymbol(
83474 'ol.interaction.KeyboardPan.handleEvent',
83475 ol.interaction.KeyboardPan.handleEvent,
83476 OPENLAYERS);
83477
83478goog.exportSymbol(
83479 'ol.interaction.KeyboardZoom',
83480 ol.interaction.KeyboardZoom,
83481 OPENLAYERS);
83482
83483goog.exportSymbol(
83484 'ol.interaction.KeyboardZoom.handleEvent',
83485 ol.interaction.KeyboardZoom.handleEvent,
83486 OPENLAYERS);
83487
83488goog.exportSymbol(
83489 'ol.interaction.Modify',
83490 ol.interaction.Modify,
83491 OPENLAYERS);
83492
83493goog.exportSymbol(
83494 'ol.interaction.Modify.handleEvent',
83495 ol.interaction.Modify.handleEvent,
83496 OPENLAYERS);
83497
83498goog.exportProperty(
83499 ol.interaction.Modify.prototype,
83500 'removePoint',
83501 ol.interaction.Modify.prototype.removePoint);
83502
83503goog.exportProperty(
83504 ol.interaction.Modify.Event.prototype,
83505 'features',
83506 ol.interaction.Modify.Event.prototype.features);
83507
83508goog.exportProperty(
83509 ol.interaction.Modify.Event.prototype,
83510 'mapBrowserEvent',
83511 ol.interaction.Modify.Event.prototype.mapBrowserEvent);
83512
83513goog.exportSymbol(
83514 'ol.interaction.MouseWheelZoom',
83515 ol.interaction.MouseWheelZoom,
83516 OPENLAYERS);
83517
83518goog.exportSymbol(
83519 'ol.interaction.MouseWheelZoom.handleEvent',
83520 ol.interaction.MouseWheelZoom.handleEvent,
83521 OPENLAYERS);
83522
83523goog.exportProperty(
83524 ol.interaction.MouseWheelZoom.prototype,
83525 'setMouseAnchor',
83526 ol.interaction.MouseWheelZoom.prototype.setMouseAnchor);
83527
83528goog.exportSymbol(
83529 'ol.interaction.PinchRotate',
83530 ol.interaction.PinchRotate,
83531 OPENLAYERS);
83532
83533goog.exportSymbol(
83534 'ol.interaction.PinchZoom',
83535 ol.interaction.PinchZoom,
83536 OPENLAYERS);
83537
83538goog.exportSymbol(
83539 'ol.interaction.Pointer',
83540 ol.interaction.Pointer,
83541 OPENLAYERS);
83542
83543goog.exportSymbol(
83544 'ol.interaction.Pointer.handleEvent',
83545 ol.interaction.Pointer.handleEvent,
83546 OPENLAYERS);
83547
83548goog.exportSymbol(
83549 'ol.interaction.Select',
83550 ol.interaction.Select,
83551 OPENLAYERS);
83552
83553goog.exportProperty(
83554 ol.interaction.Select.prototype,
83555 'getFeatures',
83556 ol.interaction.Select.prototype.getFeatures);
83557
83558goog.exportProperty(
83559 ol.interaction.Select.prototype,
83560 'getHitTolerance',
83561 ol.interaction.Select.prototype.getHitTolerance);
83562
83563goog.exportProperty(
83564 ol.interaction.Select.prototype,
83565 'getLayer',
83566 ol.interaction.Select.prototype.getLayer);
83567
83568goog.exportSymbol(
83569 'ol.interaction.Select.handleEvent',
83570 ol.interaction.Select.handleEvent,
83571 OPENLAYERS);
83572
83573goog.exportProperty(
83574 ol.interaction.Select.prototype,
83575 'setHitTolerance',
83576 ol.interaction.Select.prototype.setHitTolerance);
83577
83578goog.exportProperty(
83579 ol.interaction.Select.prototype,
83580 'setMap',
83581 ol.interaction.Select.prototype.setMap);
83582
83583goog.exportProperty(
83584 ol.interaction.Select.Event.prototype,
83585 'selected',
83586 ol.interaction.Select.Event.prototype.selected);
83587
83588goog.exportProperty(
83589 ol.interaction.Select.Event.prototype,
83590 'deselected',
83591 ol.interaction.Select.Event.prototype.deselected);
83592
83593goog.exportProperty(
83594 ol.interaction.Select.Event.prototype,
83595 'mapBrowserEvent',
83596 ol.interaction.Select.Event.prototype.mapBrowserEvent);
83597
83598goog.exportSymbol(
83599 'ol.interaction.Snap',
83600 ol.interaction.Snap,
83601 OPENLAYERS);
83602
83603goog.exportProperty(
83604 ol.interaction.Snap.prototype,
83605 'addFeature',
83606 ol.interaction.Snap.prototype.addFeature);
83607
83608goog.exportProperty(
83609 ol.interaction.Snap.prototype,
83610 'removeFeature',
83611 ol.interaction.Snap.prototype.removeFeature);
83612
83613goog.exportSymbol(
83614 'ol.interaction.Translate',
83615 ol.interaction.Translate,
83616 OPENLAYERS);
83617
83618goog.exportProperty(
83619 ol.interaction.Translate.prototype,
83620 'getHitTolerance',
83621 ol.interaction.Translate.prototype.getHitTolerance);
83622
83623goog.exportProperty(
83624 ol.interaction.Translate.prototype,
83625 'setHitTolerance',
83626 ol.interaction.Translate.prototype.setHitTolerance);
83627
83628goog.exportProperty(
83629 ol.interaction.Translate.Event.prototype,
83630 'features',
83631 ol.interaction.Translate.Event.prototype.features);
83632
83633goog.exportProperty(
83634 ol.interaction.Translate.Event.prototype,
83635 'coordinate',
83636 ol.interaction.Translate.Event.prototype.coordinate);
83637
83638goog.exportSymbol(
83639 'ol.geom.Circle',
83640 ol.geom.Circle,
83641 OPENLAYERS);
83642
83643goog.exportProperty(
83644 ol.geom.Circle.prototype,
83645 'clone',
83646 ol.geom.Circle.prototype.clone);
83647
83648goog.exportProperty(
83649 ol.geom.Circle.prototype,
83650 'getCenter',
83651 ol.geom.Circle.prototype.getCenter);
83652
83653goog.exportProperty(
83654 ol.geom.Circle.prototype,
83655 'getRadius',
83656 ol.geom.Circle.prototype.getRadius);
83657
83658goog.exportProperty(
83659 ol.geom.Circle.prototype,
83660 'getType',
83661 ol.geom.Circle.prototype.getType);
83662
83663goog.exportProperty(
83664 ol.geom.Circle.prototype,
83665 'intersectsExtent',
83666 ol.geom.Circle.prototype.intersectsExtent);
83667
83668goog.exportProperty(
83669 ol.geom.Circle.prototype,
83670 'setCenter',
83671 ol.geom.Circle.prototype.setCenter);
83672
83673goog.exportProperty(
83674 ol.geom.Circle.prototype,
83675 'setCenterAndRadius',
83676 ol.geom.Circle.prototype.setCenterAndRadius);
83677
83678goog.exportProperty(
83679 ol.geom.Circle.prototype,
83680 'setRadius',
83681 ol.geom.Circle.prototype.setRadius);
83682
83683goog.exportProperty(
83684 ol.geom.Circle.prototype,
83685 'transform',
83686 ol.geom.Circle.prototype.transform);
83687
83688goog.exportSymbol(
83689 'ol.geom.Geometry',
83690 ol.geom.Geometry,
83691 OPENLAYERS);
83692
83693goog.exportProperty(
83694 ol.geom.Geometry.prototype,
83695 'getClosestPoint',
83696 ol.geom.Geometry.prototype.getClosestPoint);
83697
83698goog.exportProperty(
83699 ol.geom.Geometry.prototype,
83700 'intersectsCoordinate',
83701 ol.geom.Geometry.prototype.intersectsCoordinate);
83702
83703goog.exportProperty(
83704 ol.geom.Geometry.prototype,
83705 'getExtent',
83706 ol.geom.Geometry.prototype.getExtent);
83707
83708goog.exportProperty(
83709 ol.geom.Geometry.prototype,
83710 'rotate',
83711 ol.geom.Geometry.prototype.rotate);
83712
83713goog.exportProperty(
83714 ol.geom.Geometry.prototype,
83715 'scale',
83716 ol.geom.Geometry.prototype.scale);
83717
83718goog.exportProperty(
83719 ol.geom.Geometry.prototype,
83720 'simplify',
83721 ol.geom.Geometry.prototype.simplify);
83722
83723goog.exportProperty(
83724 ol.geom.Geometry.prototype,
83725 'transform',
83726 ol.geom.Geometry.prototype.transform);
83727
83728goog.exportSymbol(
83729 'ol.geom.GeometryCollection',
83730 ol.geom.GeometryCollection,
83731 OPENLAYERS);
83732
83733goog.exportProperty(
83734 ol.geom.GeometryCollection.prototype,
83735 'clone',
83736 ol.geom.GeometryCollection.prototype.clone);
83737
83738goog.exportProperty(
83739 ol.geom.GeometryCollection.prototype,
83740 'getGeometries',
83741 ol.geom.GeometryCollection.prototype.getGeometries);
83742
83743goog.exportProperty(
83744 ol.geom.GeometryCollection.prototype,
83745 'getType',
83746 ol.geom.GeometryCollection.prototype.getType);
83747
83748goog.exportProperty(
83749 ol.geom.GeometryCollection.prototype,
83750 'intersectsExtent',
83751 ol.geom.GeometryCollection.prototype.intersectsExtent);
83752
83753goog.exportProperty(
83754 ol.geom.GeometryCollection.prototype,
83755 'setGeometries',
83756 ol.geom.GeometryCollection.prototype.setGeometries);
83757
83758goog.exportProperty(
83759 ol.geom.GeometryCollection.prototype,
83760 'applyTransform',
83761 ol.geom.GeometryCollection.prototype.applyTransform);
83762
83763goog.exportProperty(
83764 ol.geom.GeometryCollection.prototype,
83765 'translate',
83766 ol.geom.GeometryCollection.prototype.translate);
83767
83768goog.exportSymbol(
83769 'ol.geom.LinearRing',
83770 ol.geom.LinearRing,
83771 OPENLAYERS);
83772
83773goog.exportProperty(
83774 ol.geom.LinearRing.prototype,
83775 'clone',
83776 ol.geom.LinearRing.prototype.clone);
83777
83778goog.exportProperty(
83779 ol.geom.LinearRing.prototype,
83780 'getArea',
83781 ol.geom.LinearRing.prototype.getArea);
83782
83783goog.exportProperty(
83784 ol.geom.LinearRing.prototype,
83785 'getCoordinates',
83786 ol.geom.LinearRing.prototype.getCoordinates);
83787
83788goog.exportProperty(
83789 ol.geom.LinearRing.prototype,
83790 'getType',
83791 ol.geom.LinearRing.prototype.getType);
83792
83793goog.exportProperty(
83794 ol.geom.LinearRing.prototype,
83795 'setCoordinates',
83796 ol.geom.LinearRing.prototype.setCoordinates);
83797
83798goog.exportSymbol(
83799 'ol.geom.LineString',
83800 ol.geom.LineString,
83801 OPENLAYERS);
83802
83803goog.exportProperty(
83804 ol.geom.LineString.prototype,
83805 'appendCoordinate',
83806 ol.geom.LineString.prototype.appendCoordinate);
83807
83808goog.exportProperty(
83809 ol.geom.LineString.prototype,
83810 'clone',
83811 ol.geom.LineString.prototype.clone);
83812
83813goog.exportProperty(
83814 ol.geom.LineString.prototype,
83815 'forEachSegment',
83816 ol.geom.LineString.prototype.forEachSegment);
83817
83818goog.exportProperty(
83819 ol.geom.LineString.prototype,
83820 'getCoordinateAtM',
83821 ol.geom.LineString.prototype.getCoordinateAtM);
83822
83823goog.exportProperty(
83824 ol.geom.LineString.prototype,
83825 'getCoordinates',
83826 ol.geom.LineString.prototype.getCoordinates);
83827
83828goog.exportProperty(
83829 ol.geom.LineString.prototype,
83830 'getCoordinateAt',
83831 ol.geom.LineString.prototype.getCoordinateAt);
83832
83833goog.exportProperty(
83834 ol.geom.LineString.prototype,
83835 'getLength',
83836 ol.geom.LineString.prototype.getLength);
83837
83838goog.exportProperty(
83839 ol.geom.LineString.prototype,
83840 'getType',
83841 ol.geom.LineString.prototype.getType);
83842
83843goog.exportProperty(
83844 ol.geom.LineString.prototype,
83845 'intersectsExtent',
83846 ol.geom.LineString.prototype.intersectsExtent);
83847
83848goog.exportProperty(
83849 ol.geom.LineString.prototype,
83850 'setCoordinates',
83851 ol.geom.LineString.prototype.setCoordinates);
83852
83853goog.exportSymbol(
83854 'ol.geom.MultiLineString',
83855 ol.geom.MultiLineString,
83856 OPENLAYERS);
83857
83858goog.exportProperty(
83859 ol.geom.MultiLineString.prototype,
83860 'appendLineString',
83861 ol.geom.MultiLineString.prototype.appendLineString);
83862
83863goog.exportProperty(
83864 ol.geom.MultiLineString.prototype,
83865 'clone',
83866 ol.geom.MultiLineString.prototype.clone);
83867
83868goog.exportProperty(
83869 ol.geom.MultiLineString.prototype,
83870 'getCoordinateAtM',
83871 ol.geom.MultiLineString.prototype.getCoordinateAtM);
83872
83873goog.exportProperty(
83874 ol.geom.MultiLineString.prototype,
83875 'getCoordinates',
83876 ol.geom.MultiLineString.prototype.getCoordinates);
83877
83878goog.exportProperty(
83879 ol.geom.MultiLineString.prototype,
83880 'getLineString',
83881 ol.geom.MultiLineString.prototype.getLineString);
83882
83883goog.exportProperty(
83884 ol.geom.MultiLineString.prototype,
83885 'getLineStrings',
83886 ol.geom.MultiLineString.prototype.getLineStrings);
83887
83888goog.exportProperty(
83889 ol.geom.MultiLineString.prototype,
83890 'getType',
83891 ol.geom.MultiLineString.prototype.getType);
83892
83893goog.exportProperty(
83894 ol.geom.MultiLineString.prototype,
83895 'intersectsExtent',
83896 ol.geom.MultiLineString.prototype.intersectsExtent);
83897
83898goog.exportProperty(
83899 ol.geom.MultiLineString.prototype,
83900 'setCoordinates',
83901 ol.geom.MultiLineString.prototype.setCoordinates);
83902
83903goog.exportSymbol(
83904 'ol.geom.MultiPoint',
83905 ol.geom.MultiPoint,
83906 OPENLAYERS);
83907
83908goog.exportProperty(
83909 ol.geom.MultiPoint.prototype,
83910 'appendPoint',
83911 ol.geom.MultiPoint.prototype.appendPoint);
83912
83913goog.exportProperty(
83914 ol.geom.MultiPoint.prototype,
83915 'clone',
83916 ol.geom.MultiPoint.prototype.clone);
83917
83918goog.exportProperty(
83919 ol.geom.MultiPoint.prototype,
83920 'getCoordinates',
83921 ol.geom.MultiPoint.prototype.getCoordinates);
83922
83923goog.exportProperty(
83924 ol.geom.MultiPoint.prototype,
83925 'getPoint',
83926 ol.geom.MultiPoint.prototype.getPoint);
83927
83928goog.exportProperty(
83929 ol.geom.MultiPoint.prototype,
83930 'getPoints',
83931 ol.geom.MultiPoint.prototype.getPoints);
83932
83933goog.exportProperty(
83934 ol.geom.MultiPoint.prototype,
83935 'getType',
83936 ol.geom.MultiPoint.prototype.getType);
83937
83938goog.exportProperty(
83939 ol.geom.MultiPoint.prototype,
83940 'intersectsExtent',
83941 ol.geom.MultiPoint.prototype.intersectsExtent);
83942
83943goog.exportProperty(
83944 ol.geom.MultiPoint.prototype,
83945 'setCoordinates',
83946 ol.geom.MultiPoint.prototype.setCoordinates);
83947
83948goog.exportSymbol(
83949 'ol.geom.MultiPolygon',
83950 ol.geom.MultiPolygon,
83951 OPENLAYERS);
83952
83953goog.exportProperty(
83954 ol.geom.MultiPolygon.prototype,
83955 'appendPolygon',
83956 ol.geom.MultiPolygon.prototype.appendPolygon);
83957
83958goog.exportProperty(
83959 ol.geom.MultiPolygon.prototype,
83960 'clone',
83961 ol.geom.MultiPolygon.prototype.clone);
83962
83963goog.exportProperty(
83964 ol.geom.MultiPolygon.prototype,
83965 'getArea',
83966 ol.geom.MultiPolygon.prototype.getArea);
83967
83968goog.exportProperty(
83969 ol.geom.MultiPolygon.prototype,
83970 'getCoordinates',
83971 ol.geom.MultiPolygon.prototype.getCoordinates);
83972
83973goog.exportProperty(
83974 ol.geom.MultiPolygon.prototype,
83975 'getInteriorPoints',
83976 ol.geom.MultiPolygon.prototype.getInteriorPoints);
83977
83978goog.exportProperty(
83979 ol.geom.MultiPolygon.prototype,
83980 'getPolygon',
83981 ol.geom.MultiPolygon.prototype.getPolygon);
83982
83983goog.exportProperty(
83984 ol.geom.MultiPolygon.prototype,
83985 'getPolygons',
83986 ol.geom.MultiPolygon.prototype.getPolygons);
83987
83988goog.exportProperty(
83989 ol.geom.MultiPolygon.prototype,
83990 'getType',
83991 ol.geom.MultiPolygon.prototype.getType);
83992
83993goog.exportProperty(
83994 ol.geom.MultiPolygon.prototype,
83995 'intersectsExtent',
83996 ol.geom.MultiPolygon.prototype.intersectsExtent);
83997
83998goog.exportProperty(
83999 ol.geom.MultiPolygon.prototype,
84000 'setCoordinates',
84001 ol.geom.MultiPolygon.prototype.setCoordinates);
84002
84003goog.exportSymbol(
84004 'ol.geom.Point',
84005 ol.geom.Point,
84006 OPENLAYERS);
84007
84008goog.exportProperty(
84009 ol.geom.Point.prototype,
84010 'clone',
84011 ol.geom.Point.prototype.clone);
84012
84013goog.exportProperty(
84014 ol.geom.Point.prototype,
84015 'getCoordinates',
84016 ol.geom.Point.prototype.getCoordinates);
84017
84018goog.exportProperty(
84019 ol.geom.Point.prototype,
84020 'getType',
84021 ol.geom.Point.prototype.getType);
84022
84023goog.exportProperty(
84024 ol.geom.Point.prototype,
84025 'intersectsExtent',
84026 ol.geom.Point.prototype.intersectsExtent);
84027
84028goog.exportProperty(
84029 ol.geom.Point.prototype,
84030 'setCoordinates',
84031 ol.geom.Point.prototype.setCoordinates);
84032
84033goog.exportSymbol(
84034 'ol.geom.Polygon',
84035 ol.geom.Polygon,
84036 OPENLAYERS);
84037
84038goog.exportProperty(
84039 ol.geom.Polygon.prototype,
84040 'appendLinearRing',
84041 ol.geom.Polygon.prototype.appendLinearRing);
84042
84043goog.exportProperty(
84044 ol.geom.Polygon.prototype,
84045 'clone',
84046 ol.geom.Polygon.prototype.clone);
84047
84048goog.exportProperty(
84049 ol.geom.Polygon.prototype,
84050 'getArea',
84051 ol.geom.Polygon.prototype.getArea);
84052
84053goog.exportProperty(
84054 ol.geom.Polygon.prototype,
84055 'getCoordinates',
84056 ol.geom.Polygon.prototype.getCoordinates);
84057
84058goog.exportProperty(
84059 ol.geom.Polygon.prototype,
84060 'getInteriorPoint',
84061 ol.geom.Polygon.prototype.getInteriorPoint);
84062
84063goog.exportProperty(
84064 ol.geom.Polygon.prototype,
84065 'getLinearRingCount',
84066 ol.geom.Polygon.prototype.getLinearRingCount);
84067
84068goog.exportProperty(
84069 ol.geom.Polygon.prototype,
84070 'getLinearRing',
84071 ol.geom.Polygon.prototype.getLinearRing);
84072
84073goog.exportProperty(
84074 ol.geom.Polygon.prototype,
84075 'getLinearRings',
84076 ol.geom.Polygon.prototype.getLinearRings);
84077
84078goog.exportProperty(
84079 ol.geom.Polygon.prototype,
84080 'getType',
84081 ol.geom.Polygon.prototype.getType);
84082
84083goog.exportProperty(
84084 ol.geom.Polygon.prototype,
84085 'intersectsExtent',
84086 ol.geom.Polygon.prototype.intersectsExtent);
84087
84088goog.exportProperty(
84089 ol.geom.Polygon.prototype,
84090 'setCoordinates',
84091 ol.geom.Polygon.prototype.setCoordinates);
84092
84093goog.exportSymbol(
84094 'ol.geom.Polygon.circular',
84095 ol.geom.Polygon.circular,
84096 OPENLAYERS);
84097
84098goog.exportSymbol(
84099 'ol.geom.Polygon.fromExtent',
84100 ol.geom.Polygon.fromExtent,
84101 OPENLAYERS);
84102
84103goog.exportSymbol(
84104 'ol.geom.Polygon.fromCircle',
84105 ol.geom.Polygon.fromCircle,
84106 OPENLAYERS);
84107
84108goog.exportSymbol(
84109 'ol.geom.SimpleGeometry',
84110 ol.geom.SimpleGeometry,
84111 OPENLAYERS);
84112
84113goog.exportProperty(
84114 ol.geom.SimpleGeometry.prototype,
84115 'getFirstCoordinate',
84116 ol.geom.SimpleGeometry.prototype.getFirstCoordinate);
84117
84118goog.exportProperty(
84119 ol.geom.SimpleGeometry.prototype,
84120 'getLastCoordinate',
84121 ol.geom.SimpleGeometry.prototype.getLastCoordinate);
84122
84123goog.exportProperty(
84124 ol.geom.SimpleGeometry.prototype,
84125 'getLayout',
84126 ol.geom.SimpleGeometry.prototype.getLayout);
84127
84128goog.exportProperty(
84129 ol.geom.SimpleGeometry.prototype,
84130 'applyTransform',
84131 ol.geom.SimpleGeometry.prototype.applyTransform);
84132
84133goog.exportProperty(
84134 ol.geom.SimpleGeometry.prototype,
84135 'translate',
84136 ol.geom.SimpleGeometry.prototype.translate);
84137
84138goog.exportSymbol(
84139 'ol.format.EsriJSON',
84140 ol.format.EsriJSON,
84141 OPENLAYERS);
84142
84143goog.exportProperty(
84144 ol.format.EsriJSON.prototype,
84145 'readFeature',
84146 ol.format.EsriJSON.prototype.readFeature);
84147
84148goog.exportProperty(
84149 ol.format.EsriJSON.prototype,
84150 'readFeatures',
84151 ol.format.EsriJSON.prototype.readFeatures);
84152
84153goog.exportProperty(
84154 ol.format.EsriJSON.prototype,
84155 'readGeometry',
84156 ol.format.EsriJSON.prototype.readGeometry);
84157
84158goog.exportProperty(
84159 ol.format.EsriJSON.prototype,
84160 'readProjection',
84161 ol.format.EsriJSON.prototype.readProjection);
84162
84163goog.exportProperty(
84164 ol.format.EsriJSON.prototype,
84165 'writeGeometry',
84166 ol.format.EsriJSON.prototype.writeGeometry);
84167
84168goog.exportProperty(
84169 ol.format.EsriJSON.prototype,
84170 'writeGeometryObject',
84171 ol.format.EsriJSON.prototype.writeGeometryObject);
84172
84173goog.exportProperty(
84174 ol.format.EsriJSON.prototype,
84175 'writeFeature',
84176 ol.format.EsriJSON.prototype.writeFeature);
84177
84178goog.exportProperty(
84179 ol.format.EsriJSON.prototype,
84180 'writeFeatureObject',
84181 ol.format.EsriJSON.prototype.writeFeatureObject);
84182
84183goog.exportProperty(
84184 ol.format.EsriJSON.prototype,
84185 'writeFeatures',
84186 ol.format.EsriJSON.prototype.writeFeatures);
84187
84188goog.exportProperty(
84189 ol.format.EsriJSON.prototype,
84190 'writeFeaturesObject',
84191 ol.format.EsriJSON.prototype.writeFeaturesObject);
84192
84193goog.exportSymbol(
84194 'ol.format.Feature',
84195 ol.format.Feature,
84196 OPENLAYERS);
84197
84198goog.exportSymbol(
84199 'ol.format.filter.and',
84200 ol.format.filter.and,
84201 OPENLAYERS);
84202
84203goog.exportSymbol(
84204 'ol.format.filter.or',
84205 ol.format.filter.or,
84206 OPENLAYERS);
84207
84208goog.exportSymbol(
84209 'ol.format.filter.not',
84210 ol.format.filter.not,
84211 OPENLAYERS);
84212
84213goog.exportSymbol(
84214 'ol.format.filter.bbox',
84215 ol.format.filter.bbox,
84216 OPENLAYERS);
84217
84218goog.exportSymbol(
84219 'ol.format.filter.intersects',
84220 ol.format.filter.intersects,
84221 OPENLAYERS);
84222
84223goog.exportSymbol(
84224 'ol.format.filter.within',
84225 ol.format.filter.within,
84226 OPENLAYERS);
84227
84228goog.exportSymbol(
84229 'ol.format.filter.equalTo',
84230 ol.format.filter.equalTo,
84231 OPENLAYERS);
84232
84233goog.exportSymbol(
84234 'ol.format.filter.notEqualTo',
84235 ol.format.filter.notEqualTo,
84236 OPENLAYERS);
84237
84238goog.exportSymbol(
84239 'ol.format.filter.lessThan',
84240 ol.format.filter.lessThan,
84241 OPENLAYERS);
84242
84243goog.exportSymbol(
84244 'ol.format.filter.lessThanOrEqualTo',
84245 ol.format.filter.lessThanOrEqualTo,
84246 OPENLAYERS);
84247
84248goog.exportSymbol(
84249 'ol.format.filter.greaterThan',
84250 ol.format.filter.greaterThan,
84251 OPENLAYERS);
84252
84253goog.exportSymbol(
84254 'ol.format.filter.greaterThanOrEqualTo',
84255 ol.format.filter.greaterThanOrEqualTo,
84256 OPENLAYERS);
84257
84258goog.exportSymbol(
84259 'ol.format.filter.isNull',
84260 ol.format.filter.isNull,
84261 OPENLAYERS);
84262
84263goog.exportSymbol(
84264 'ol.format.filter.between',
84265 ol.format.filter.between,
84266 OPENLAYERS);
84267
84268goog.exportSymbol(
84269 'ol.format.filter.like',
84270 ol.format.filter.like,
84271 OPENLAYERS);
84272
84273goog.exportSymbol(
84274 'ol.format.filter.during',
84275 ol.format.filter.during,
84276 OPENLAYERS);
84277
84278goog.exportSymbol(
84279 'ol.format.GeoJSON',
84280 ol.format.GeoJSON,
84281 OPENLAYERS);
84282
84283goog.exportProperty(
84284 ol.format.GeoJSON.prototype,
84285 'readFeature',
84286 ol.format.GeoJSON.prototype.readFeature);
84287
84288goog.exportProperty(
84289 ol.format.GeoJSON.prototype,
84290 'readFeatures',
84291 ol.format.GeoJSON.prototype.readFeatures);
84292
84293goog.exportProperty(
84294 ol.format.GeoJSON.prototype,
84295 'readGeometry',
84296 ol.format.GeoJSON.prototype.readGeometry);
84297
84298goog.exportProperty(
84299 ol.format.GeoJSON.prototype,
84300 'readProjection',
84301 ol.format.GeoJSON.prototype.readProjection);
84302
84303goog.exportProperty(
84304 ol.format.GeoJSON.prototype,
84305 'writeFeature',
84306 ol.format.GeoJSON.prototype.writeFeature);
84307
84308goog.exportProperty(
84309 ol.format.GeoJSON.prototype,
84310 'writeFeatureObject',
84311 ol.format.GeoJSON.prototype.writeFeatureObject);
84312
84313goog.exportProperty(
84314 ol.format.GeoJSON.prototype,
84315 'writeFeatures',
84316 ol.format.GeoJSON.prototype.writeFeatures);
84317
84318goog.exportProperty(
84319 ol.format.GeoJSON.prototype,
84320 'writeFeaturesObject',
84321 ol.format.GeoJSON.prototype.writeFeaturesObject);
84322
84323goog.exportProperty(
84324 ol.format.GeoJSON.prototype,
84325 'writeGeometry',
84326 ol.format.GeoJSON.prototype.writeGeometry);
84327
84328goog.exportProperty(
84329 ol.format.GeoJSON.prototype,
84330 'writeGeometryObject',
84331 ol.format.GeoJSON.prototype.writeGeometryObject);
84332
84333goog.exportSymbol(
84334 'ol.format.GML',
84335 ol.format.GML,
84336 OPENLAYERS);
84337
84338goog.exportProperty(
84339 ol.format.GML.prototype,
84340 'writeFeatures',
84341 ol.format.GML.prototype.writeFeatures);
84342
84343goog.exportProperty(
84344 ol.format.GML.prototype,
84345 'writeFeaturesNode',
84346 ol.format.GML.prototype.writeFeaturesNode);
84347
84348goog.exportSymbol(
84349 'ol.format.GML2',
84350 ol.format.GML2,
84351 OPENLAYERS);
84352
84353goog.exportSymbol(
84354 'ol.format.GML3',
84355 ol.format.GML3,
84356 OPENLAYERS);
84357
84358goog.exportProperty(
84359 ol.format.GML3.prototype,
84360 'writeGeometryNode',
84361 ol.format.GML3.prototype.writeGeometryNode);
84362
84363goog.exportProperty(
84364 ol.format.GML3.prototype,
84365 'writeFeatures',
84366 ol.format.GML3.prototype.writeFeatures);
84367
84368goog.exportProperty(
84369 ol.format.GML3.prototype,
84370 'writeFeaturesNode',
84371 ol.format.GML3.prototype.writeFeaturesNode);
84372
84373goog.exportProperty(
84374 ol.format.GMLBase.prototype,
84375 'readFeatures',
84376 ol.format.GMLBase.prototype.readFeatures);
84377
84378goog.exportSymbol(
84379 'ol.format.GPX',
84380 ol.format.GPX,
84381 OPENLAYERS);
84382
84383goog.exportProperty(
84384 ol.format.GPX.prototype,
84385 'readFeature',
84386 ol.format.GPX.prototype.readFeature);
84387
84388goog.exportProperty(
84389 ol.format.GPX.prototype,
84390 'readFeatures',
84391 ol.format.GPX.prototype.readFeatures);
84392
84393goog.exportProperty(
84394 ol.format.GPX.prototype,
84395 'readProjection',
84396 ol.format.GPX.prototype.readProjection);
84397
84398goog.exportProperty(
84399 ol.format.GPX.prototype,
84400 'writeFeatures',
84401 ol.format.GPX.prototype.writeFeatures);
84402
84403goog.exportProperty(
84404 ol.format.GPX.prototype,
84405 'writeFeaturesNode',
84406 ol.format.GPX.prototype.writeFeaturesNode);
84407
84408goog.exportSymbol(
84409 'ol.format.IGC',
84410 ol.format.IGC,
84411 OPENLAYERS);
84412
84413goog.exportProperty(
84414 ol.format.IGC.prototype,
84415 'readFeature',
84416 ol.format.IGC.prototype.readFeature);
84417
84418goog.exportProperty(
84419 ol.format.IGC.prototype,
84420 'readFeatures',
84421 ol.format.IGC.prototype.readFeatures);
84422
84423goog.exportProperty(
84424 ol.format.IGC.prototype,
84425 'readProjection',
84426 ol.format.IGC.prototype.readProjection);
84427
84428goog.exportSymbol(
84429 'ol.format.KML',
84430 ol.format.KML,
84431 OPENLAYERS);
84432
84433goog.exportProperty(
84434 ol.format.KML.prototype,
84435 'readFeature',
84436 ol.format.KML.prototype.readFeature);
84437
84438goog.exportProperty(
84439 ol.format.KML.prototype,
84440 'readFeatures',
84441 ol.format.KML.prototype.readFeatures);
84442
84443goog.exportProperty(
84444 ol.format.KML.prototype,
84445 'readName',
84446 ol.format.KML.prototype.readName);
84447
84448goog.exportProperty(
84449 ol.format.KML.prototype,
84450 'readNetworkLinks',
84451 ol.format.KML.prototype.readNetworkLinks);
84452
84453goog.exportProperty(
84454 ol.format.KML.prototype,
84455 'readRegion',
84456 ol.format.KML.prototype.readRegion);
84457
84458goog.exportProperty(
84459 ol.format.KML.prototype,
84460 'readRegionFromNode',
84461 ol.format.KML.prototype.readRegionFromNode);
84462
84463goog.exportProperty(
84464 ol.format.KML.prototype,
84465 'readProjection',
84466 ol.format.KML.prototype.readProjection);
84467
84468goog.exportProperty(
84469 ol.format.KML.prototype,
84470 'writeFeatures',
84471 ol.format.KML.prototype.writeFeatures);
84472
84473goog.exportProperty(
84474 ol.format.KML.prototype,
84475 'writeFeaturesNode',
84476 ol.format.KML.prototype.writeFeaturesNode);
84477
84478goog.exportSymbol(
84479 'ol.format.MVT',
84480 ol.format.MVT,
84481 OPENLAYERS);
84482
84483goog.exportProperty(
84484 ol.format.MVT.prototype,
84485 'getLastExtent',
84486 ol.format.MVT.prototype.getLastExtent);
84487
84488goog.exportProperty(
84489 ol.format.MVT.prototype,
84490 'readFeatures',
84491 ol.format.MVT.prototype.readFeatures);
84492
84493goog.exportProperty(
84494 ol.format.MVT.prototype,
84495 'readProjection',
84496 ol.format.MVT.prototype.readProjection);
84497
84498goog.exportProperty(
84499 ol.format.MVT.prototype,
84500 'setLayers',
84501 ol.format.MVT.prototype.setLayers);
84502
84503goog.exportSymbol(
84504 'ol.format.OSMXML',
84505 ol.format.OSMXML,
84506 OPENLAYERS);
84507
84508goog.exportProperty(
84509 ol.format.OSMXML.prototype,
84510 'readFeatures',
84511 ol.format.OSMXML.prototype.readFeatures);
84512
84513goog.exportProperty(
84514 ol.format.OSMXML.prototype,
84515 'readProjection',
84516 ol.format.OSMXML.prototype.readProjection);
84517
84518goog.exportSymbol(
84519 'ol.format.Polyline',
84520 ol.format.Polyline,
84521 OPENLAYERS);
84522
84523goog.exportSymbol(
84524 'ol.format.Polyline.encodeDeltas',
84525 ol.format.Polyline.encodeDeltas,
84526 OPENLAYERS);
84527
84528goog.exportSymbol(
84529 'ol.format.Polyline.decodeDeltas',
84530 ol.format.Polyline.decodeDeltas,
84531 OPENLAYERS);
84532
84533goog.exportSymbol(
84534 'ol.format.Polyline.encodeFloats',
84535 ol.format.Polyline.encodeFloats,
84536 OPENLAYERS);
84537
84538goog.exportSymbol(
84539 'ol.format.Polyline.decodeFloats',
84540 ol.format.Polyline.decodeFloats,
84541 OPENLAYERS);
84542
84543goog.exportProperty(
84544 ol.format.Polyline.prototype,
84545 'readFeature',
84546 ol.format.Polyline.prototype.readFeature);
84547
84548goog.exportProperty(
84549 ol.format.Polyline.prototype,
84550 'readFeatures',
84551 ol.format.Polyline.prototype.readFeatures);
84552
84553goog.exportProperty(
84554 ol.format.Polyline.prototype,
84555 'readGeometry',
84556 ol.format.Polyline.prototype.readGeometry);
84557
84558goog.exportProperty(
84559 ol.format.Polyline.prototype,
84560 'readProjection',
84561 ol.format.Polyline.prototype.readProjection);
84562
84563goog.exportProperty(
84564 ol.format.Polyline.prototype,
84565 'writeGeometry',
84566 ol.format.Polyline.prototype.writeGeometry);
84567
84568goog.exportSymbol(
84569 'ol.format.TopoJSON',
84570 ol.format.TopoJSON,
84571 OPENLAYERS);
84572
84573goog.exportProperty(
84574 ol.format.TopoJSON.prototype,
84575 'readFeatures',
84576 ol.format.TopoJSON.prototype.readFeatures);
84577
84578goog.exportProperty(
84579 ol.format.TopoJSON.prototype,
84580 'readProjection',
84581 ol.format.TopoJSON.prototype.readProjection);
84582
84583goog.exportSymbol(
84584 'ol.format.WFS',
84585 ol.format.WFS,
84586 OPENLAYERS);
84587
84588goog.exportProperty(
84589 ol.format.WFS.prototype,
84590 'readFeatures',
84591 ol.format.WFS.prototype.readFeatures);
84592
84593goog.exportProperty(
84594 ol.format.WFS.prototype,
84595 'readTransactionResponse',
84596 ol.format.WFS.prototype.readTransactionResponse);
84597
84598goog.exportProperty(
84599 ol.format.WFS.prototype,
84600 'readFeatureCollectionMetadata',
84601 ol.format.WFS.prototype.readFeatureCollectionMetadata);
84602
84603goog.exportSymbol(
84604 'ol.format.WFS.writeFilter',
84605 ol.format.WFS.writeFilter,
84606 OPENLAYERS);
84607
84608goog.exportProperty(
84609 ol.format.WFS.prototype,
84610 'writeGetFeature',
84611 ol.format.WFS.prototype.writeGetFeature);
84612
84613goog.exportProperty(
84614 ol.format.WFS.prototype,
84615 'writeTransaction',
84616 ol.format.WFS.prototype.writeTransaction);
84617
84618goog.exportProperty(
84619 ol.format.WFS.prototype,
84620 'readProjection',
84621 ol.format.WFS.prototype.readProjection);
84622
84623goog.exportSymbol(
84624 'ol.format.WKT',
84625 ol.format.WKT,
84626 OPENLAYERS);
84627
84628goog.exportProperty(
84629 ol.format.WKT.prototype,
84630 'readFeature',
84631 ol.format.WKT.prototype.readFeature);
84632
84633goog.exportProperty(
84634 ol.format.WKT.prototype,
84635 'readFeatures',
84636 ol.format.WKT.prototype.readFeatures);
84637
84638goog.exportProperty(
84639 ol.format.WKT.prototype,
84640 'readGeometry',
84641 ol.format.WKT.prototype.readGeometry);
84642
84643goog.exportProperty(
84644 ol.format.WKT.prototype,
84645 'writeFeature',
84646 ol.format.WKT.prototype.writeFeature);
84647
84648goog.exportProperty(
84649 ol.format.WKT.prototype,
84650 'writeFeatures',
84651 ol.format.WKT.prototype.writeFeatures);
84652
84653goog.exportProperty(
84654 ol.format.WKT.prototype,
84655 'writeGeometry',
84656 ol.format.WKT.prototype.writeGeometry);
84657
84658goog.exportSymbol(
84659 'ol.format.WMSCapabilities',
84660 ol.format.WMSCapabilities,
84661 OPENLAYERS);
84662
84663goog.exportProperty(
84664 ol.format.WMSCapabilities.prototype,
84665 'read',
84666 ol.format.WMSCapabilities.prototype.read);
84667
84668goog.exportSymbol(
84669 'ol.format.WMSGetFeatureInfo',
84670 ol.format.WMSGetFeatureInfo,
84671 OPENLAYERS);
84672
84673goog.exportProperty(
84674 ol.format.WMSGetFeatureInfo.prototype,
84675 'readFeatures',
84676 ol.format.WMSGetFeatureInfo.prototype.readFeatures);
84677
84678goog.exportSymbol(
84679 'ol.format.WMTSCapabilities',
84680 ol.format.WMTSCapabilities,
84681 OPENLAYERS);
84682
84683goog.exportProperty(
84684 ol.format.WMTSCapabilities.prototype,
84685 'read',
84686 ol.format.WMTSCapabilities.prototype.read);
84687
84688goog.exportSymbol(
84689 'ol.format.filter.And',
84690 ol.format.filter.And,
84691 OPENLAYERS);
84692
84693goog.exportSymbol(
84694 'ol.format.filter.Bbox',
84695 ol.format.filter.Bbox,
84696 OPENLAYERS);
84697
84698goog.exportSymbol(
84699 'ol.format.filter.Comparison',
84700 ol.format.filter.Comparison,
84701 OPENLAYERS);
84702
84703goog.exportSymbol(
84704 'ol.format.filter.ComparisonBinary',
84705 ol.format.filter.ComparisonBinary,
84706 OPENLAYERS);
84707
84708goog.exportSymbol(
84709 'ol.format.filter.During',
84710 ol.format.filter.During,
84711 OPENLAYERS);
84712
84713goog.exportSymbol(
84714 'ol.format.filter.EqualTo',
84715 ol.format.filter.EqualTo,
84716 OPENLAYERS);
84717
84718goog.exportSymbol(
84719 'ol.format.filter.Filter',
84720 ol.format.filter.Filter,
84721 OPENLAYERS);
84722
84723goog.exportSymbol(
84724 'ol.format.filter.GreaterThan',
84725 ol.format.filter.GreaterThan,
84726 OPENLAYERS);
84727
84728goog.exportSymbol(
84729 'ol.format.filter.GreaterThanOrEqualTo',
84730 ol.format.filter.GreaterThanOrEqualTo,
84731 OPENLAYERS);
84732
84733goog.exportSymbol(
84734 'ol.format.filter.Intersects',
84735 ol.format.filter.Intersects,
84736 OPENLAYERS);
84737
84738goog.exportSymbol(
84739 'ol.format.filter.IsBetween',
84740 ol.format.filter.IsBetween,
84741 OPENLAYERS);
84742
84743goog.exportSymbol(
84744 'ol.format.filter.IsLike',
84745 ol.format.filter.IsLike,
84746 OPENLAYERS);
84747
84748goog.exportSymbol(
84749 'ol.format.filter.IsNull',
84750 ol.format.filter.IsNull,
84751 OPENLAYERS);
84752
84753goog.exportSymbol(
84754 'ol.format.filter.LessThan',
84755 ol.format.filter.LessThan,
84756 OPENLAYERS);
84757
84758goog.exportSymbol(
84759 'ol.format.filter.LessThanOrEqualTo',
84760 ol.format.filter.LessThanOrEqualTo,
84761 OPENLAYERS);
84762
84763goog.exportSymbol(
84764 'ol.format.filter.Not',
84765 ol.format.filter.Not,
84766 OPENLAYERS);
84767
84768goog.exportSymbol(
84769 'ol.format.filter.NotEqualTo',
84770 ol.format.filter.NotEqualTo,
84771 OPENLAYERS);
84772
84773goog.exportSymbol(
84774 'ol.format.filter.Or',
84775 ol.format.filter.Or,
84776 OPENLAYERS);
84777
84778goog.exportSymbol(
84779 'ol.format.filter.Spatial',
84780 ol.format.filter.Spatial,
84781 OPENLAYERS);
84782
84783goog.exportSymbol(
84784 'ol.format.filter.Within',
84785 ol.format.filter.Within,
84786 OPENLAYERS);
84787
84788goog.exportSymbol(
84789 'ol.events.condition.altKeyOnly',
84790 ol.events.condition.altKeyOnly,
84791 OPENLAYERS);
84792
84793goog.exportSymbol(
84794 'ol.events.condition.altShiftKeysOnly',
84795 ol.events.condition.altShiftKeysOnly,
84796 OPENLAYERS);
84797
84798goog.exportSymbol(
84799 'ol.events.condition.always',
84800 ol.events.condition.always,
84801 OPENLAYERS);
84802
84803goog.exportSymbol(
84804 'ol.events.condition.click',
84805 ol.events.condition.click,
84806 OPENLAYERS);
84807
84808goog.exportSymbol(
84809 'ol.events.condition.never',
84810 ol.events.condition.never,
84811 OPENLAYERS);
84812
84813goog.exportSymbol(
84814 'ol.events.condition.pointerMove',
84815 ol.events.condition.pointerMove,
84816 OPENLAYERS);
84817
84818goog.exportSymbol(
84819 'ol.events.condition.singleClick',
84820 ol.events.condition.singleClick,
84821 OPENLAYERS);
84822
84823goog.exportSymbol(
84824 'ol.events.condition.doubleClick',
84825 ol.events.condition.doubleClick,
84826 OPENLAYERS);
84827
84828goog.exportSymbol(
84829 'ol.events.condition.noModifierKeys',
84830 ol.events.condition.noModifierKeys,
84831 OPENLAYERS);
84832
84833goog.exportSymbol(
84834 'ol.events.condition.platformModifierKeyOnly',
84835 ol.events.condition.platformModifierKeyOnly,
84836 OPENLAYERS);
84837
84838goog.exportSymbol(
84839 'ol.events.condition.shiftKeyOnly',
84840 ol.events.condition.shiftKeyOnly,
84841 OPENLAYERS);
84842
84843goog.exportSymbol(
84844 'ol.events.condition.targetNotEditable',
84845 ol.events.condition.targetNotEditable,
84846 OPENLAYERS);
84847
84848goog.exportSymbol(
84849 'ol.events.condition.mouseOnly',
84850 ol.events.condition.mouseOnly,
84851 OPENLAYERS);
84852
84853goog.exportSymbol(
84854 'ol.events.condition.primaryAction',
84855 ol.events.condition.primaryAction,
84856 OPENLAYERS);
84857
84858goog.exportProperty(
84859 ol.events.Event.prototype,
84860 'type',
84861 ol.events.Event.prototype.type);
84862
84863goog.exportProperty(
84864 ol.events.Event.prototype,
84865 'target',
84866 ol.events.Event.prototype.target);
84867
84868goog.exportProperty(
84869 ol.events.Event.prototype,
84870 'preventDefault',
84871 ol.events.Event.prototype.preventDefault);
84872
84873goog.exportProperty(
84874 ol.events.Event.prototype,
84875 'stopPropagation',
84876 ol.events.Event.prototype.stopPropagation);
84877
84878goog.exportSymbol(
84879 'ol.control.Attribution',
84880 ol.control.Attribution,
84881 OPENLAYERS);
84882
84883goog.exportSymbol(
84884 'ol.control.Attribution.render',
84885 ol.control.Attribution.render,
84886 OPENLAYERS);
84887
84888goog.exportProperty(
84889 ol.control.Attribution.prototype,
84890 'getCollapsible',
84891 ol.control.Attribution.prototype.getCollapsible);
84892
84893goog.exportProperty(
84894 ol.control.Attribution.prototype,
84895 'setCollapsible',
84896 ol.control.Attribution.prototype.setCollapsible);
84897
84898goog.exportProperty(
84899 ol.control.Attribution.prototype,
84900 'setCollapsed',
84901 ol.control.Attribution.prototype.setCollapsed);
84902
84903goog.exportProperty(
84904 ol.control.Attribution.prototype,
84905 'getCollapsed',
84906 ol.control.Attribution.prototype.getCollapsed);
84907
84908goog.exportSymbol(
84909 'ol.control.Control',
84910 ol.control.Control,
84911 OPENLAYERS);
84912
84913goog.exportProperty(
84914 ol.control.Control.prototype,
84915 'getMap',
84916 ol.control.Control.prototype.getMap);
84917
84918goog.exportProperty(
84919 ol.control.Control.prototype,
84920 'setMap',
84921 ol.control.Control.prototype.setMap);
84922
84923goog.exportProperty(
84924 ol.control.Control.prototype,
84925 'setTarget',
84926 ol.control.Control.prototype.setTarget);
84927
84928goog.exportSymbol(
84929 'ol.control.FullScreen',
84930 ol.control.FullScreen,
84931 OPENLAYERS);
84932
84933goog.exportSymbol(
84934 'ol.control.MousePosition',
84935 ol.control.MousePosition,
84936 OPENLAYERS);
84937
84938goog.exportSymbol(
84939 'ol.control.MousePosition.render',
84940 ol.control.MousePosition.render,
84941 OPENLAYERS);
84942
84943goog.exportProperty(
84944 ol.control.MousePosition.prototype,
84945 'getCoordinateFormat',
84946 ol.control.MousePosition.prototype.getCoordinateFormat);
84947
84948goog.exportProperty(
84949 ol.control.MousePosition.prototype,
84950 'getProjection',
84951 ol.control.MousePosition.prototype.getProjection);
84952
84953goog.exportProperty(
84954 ol.control.MousePosition.prototype,
84955 'setCoordinateFormat',
84956 ol.control.MousePosition.prototype.setCoordinateFormat);
84957
84958goog.exportProperty(
84959 ol.control.MousePosition.prototype,
84960 'setProjection',
84961 ol.control.MousePosition.prototype.setProjection);
84962
84963goog.exportSymbol(
84964 'ol.control.OverviewMap',
84965 ol.control.OverviewMap,
84966 OPENLAYERS);
84967
84968goog.exportSymbol(
84969 'ol.control.OverviewMap.render',
84970 ol.control.OverviewMap.render,
84971 OPENLAYERS);
84972
84973goog.exportProperty(
84974 ol.control.OverviewMap.prototype,
84975 'getCollapsible',
84976 ol.control.OverviewMap.prototype.getCollapsible);
84977
84978goog.exportProperty(
84979 ol.control.OverviewMap.prototype,
84980 'setCollapsible',
84981 ol.control.OverviewMap.prototype.setCollapsible);
84982
84983goog.exportProperty(
84984 ol.control.OverviewMap.prototype,
84985 'setCollapsed',
84986 ol.control.OverviewMap.prototype.setCollapsed);
84987
84988goog.exportProperty(
84989 ol.control.OverviewMap.prototype,
84990 'getCollapsed',
84991 ol.control.OverviewMap.prototype.getCollapsed);
84992
84993goog.exportProperty(
84994 ol.control.OverviewMap.prototype,
84995 'getOverviewMap',
84996 ol.control.OverviewMap.prototype.getOverviewMap);
84997
84998goog.exportSymbol(
84999 'ol.control.Rotate',
85000 ol.control.Rotate,
85001 OPENLAYERS);
85002
85003goog.exportSymbol(
85004 'ol.control.Rotate.render',
85005 ol.control.Rotate.render,
85006 OPENLAYERS);
85007
85008goog.exportSymbol(
85009 'ol.control.ScaleLine',
85010 ol.control.ScaleLine,
85011 OPENLAYERS);
85012
85013goog.exportProperty(
85014 ol.control.ScaleLine.prototype,
85015 'getUnits',
85016 ol.control.ScaleLine.prototype.getUnits);
85017
85018goog.exportSymbol(
85019 'ol.control.ScaleLine.render',
85020 ol.control.ScaleLine.render,
85021 OPENLAYERS);
85022
85023goog.exportProperty(
85024 ol.control.ScaleLine.prototype,
85025 'setUnits',
85026 ol.control.ScaleLine.prototype.setUnits);
85027
85028goog.exportSymbol(
85029 'ol.control.Zoom',
85030 ol.control.Zoom,
85031 OPENLAYERS);
85032
85033goog.exportSymbol(
85034 'ol.control.ZoomSlider',
85035 ol.control.ZoomSlider,
85036 OPENLAYERS);
85037
85038goog.exportSymbol(
85039 'ol.control.ZoomSlider.render',
85040 ol.control.ZoomSlider.render,
85041 OPENLAYERS);
85042
85043goog.exportSymbol(
85044 'ol.control.ZoomToExtent',
85045 ol.control.ZoomToExtent,
85046 OPENLAYERS);
85047
85048goog.exportProperty(
85049 ol.Object.prototype,
85050 'changed',
85051 ol.Object.prototype.changed);
85052
85053goog.exportProperty(
85054 ol.Object.prototype,
85055 'dispatchEvent',
85056 ol.Object.prototype.dispatchEvent);
85057
85058goog.exportProperty(
85059 ol.Object.prototype,
85060 'getRevision',
85061 ol.Object.prototype.getRevision);
85062
85063goog.exportProperty(
85064 ol.Object.prototype,
85065 'on',
85066 ol.Object.prototype.on);
85067
85068goog.exportProperty(
85069 ol.Object.prototype,
85070 'once',
85071 ol.Object.prototype.once);
85072
85073goog.exportProperty(
85074 ol.Object.prototype,
85075 'un',
85076 ol.Object.prototype.un);
85077
85078goog.exportProperty(
85079 ol.Collection.prototype,
85080 'get',
85081 ol.Collection.prototype.get);
85082
85083goog.exportProperty(
85084 ol.Collection.prototype,
85085 'getKeys',
85086 ol.Collection.prototype.getKeys);
85087
85088goog.exportProperty(
85089 ol.Collection.prototype,
85090 'getProperties',
85091 ol.Collection.prototype.getProperties);
85092
85093goog.exportProperty(
85094 ol.Collection.prototype,
85095 'set',
85096 ol.Collection.prototype.set);
85097
85098goog.exportProperty(
85099 ol.Collection.prototype,
85100 'setProperties',
85101 ol.Collection.prototype.setProperties);
85102
85103goog.exportProperty(
85104 ol.Collection.prototype,
85105 'unset',
85106 ol.Collection.prototype.unset);
85107
85108goog.exportProperty(
85109 ol.Collection.prototype,
85110 'changed',
85111 ol.Collection.prototype.changed);
85112
85113goog.exportProperty(
85114 ol.Collection.prototype,
85115 'dispatchEvent',
85116 ol.Collection.prototype.dispatchEvent);
85117
85118goog.exportProperty(
85119 ol.Collection.prototype,
85120 'getRevision',
85121 ol.Collection.prototype.getRevision);
85122
85123goog.exportProperty(
85124 ol.Collection.prototype,
85125 'on',
85126 ol.Collection.prototype.on);
85127
85128goog.exportProperty(
85129 ol.Collection.prototype,
85130 'once',
85131 ol.Collection.prototype.once);
85132
85133goog.exportProperty(
85134 ol.Collection.prototype,
85135 'un',
85136 ol.Collection.prototype.un);
85137
85138goog.exportProperty(
85139 ol.Collection.Event.prototype,
85140 'type',
85141 ol.Collection.Event.prototype.type);
85142
85143goog.exportProperty(
85144 ol.Collection.Event.prototype,
85145 'target',
85146 ol.Collection.Event.prototype.target);
85147
85148goog.exportProperty(
85149 ol.Collection.Event.prototype,
85150 'preventDefault',
85151 ol.Collection.Event.prototype.preventDefault);
85152
85153goog.exportProperty(
85154 ol.Collection.Event.prototype,
85155 'stopPropagation',
85156 ol.Collection.Event.prototype.stopPropagation);
85157
85158goog.exportProperty(
85159 ol.DeviceOrientation.prototype,
85160 'get',
85161 ol.DeviceOrientation.prototype.get);
85162
85163goog.exportProperty(
85164 ol.DeviceOrientation.prototype,
85165 'getKeys',
85166 ol.DeviceOrientation.prototype.getKeys);
85167
85168goog.exportProperty(
85169 ol.DeviceOrientation.prototype,
85170 'getProperties',
85171 ol.DeviceOrientation.prototype.getProperties);
85172
85173goog.exportProperty(
85174 ol.DeviceOrientation.prototype,
85175 'set',
85176 ol.DeviceOrientation.prototype.set);
85177
85178goog.exportProperty(
85179 ol.DeviceOrientation.prototype,
85180 'setProperties',
85181 ol.DeviceOrientation.prototype.setProperties);
85182
85183goog.exportProperty(
85184 ol.DeviceOrientation.prototype,
85185 'unset',
85186 ol.DeviceOrientation.prototype.unset);
85187
85188goog.exportProperty(
85189 ol.DeviceOrientation.prototype,
85190 'changed',
85191 ol.DeviceOrientation.prototype.changed);
85192
85193goog.exportProperty(
85194 ol.DeviceOrientation.prototype,
85195 'dispatchEvent',
85196 ol.DeviceOrientation.prototype.dispatchEvent);
85197
85198goog.exportProperty(
85199 ol.DeviceOrientation.prototype,
85200 'getRevision',
85201 ol.DeviceOrientation.prototype.getRevision);
85202
85203goog.exportProperty(
85204 ol.DeviceOrientation.prototype,
85205 'on',
85206 ol.DeviceOrientation.prototype.on);
85207
85208goog.exportProperty(
85209 ol.DeviceOrientation.prototype,
85210 'once',
85211 ol.DeviceOrientation.prototype.once);
85212
85213goog.exportProperty(
85214 ol.DeviceOrientation.prototype,
85215 'un',
85216 ol.DeviceOrientation.prototype.un);
85217
85218goog.exportProperty(
85219 ol.Feature.prototype,
85220 'get',
85221 ol.Feature.prototype.get);
85222
85223goog.exportProperty(
85224 ol.Feature.prototype,
85225 'getKeys',
85226 ol.Feature.prototype.getKeys);
85227
85228goog.exportProperty(
85229 ol.Feature.prototype,
85230 'getProperties',
85231 ol.Feature.prototype.getProperties);
85232
85233goog.exportProperty(
85234 ol.Feature.prototype,
85235 'set',
85236 ol.Feature.prototype.set);
85237
85238goog.exportProperty(
85239 ol.Feature.prototype,
85240 'setProperties',
85241 ol.Feature.prototype.setProperties);
85242
85243goog.exportProperty(
85244 ol.Feature.prototype,
85245 'unset',
85246 ol.Feature.prototype.unset);
85247
85248goog.exportProperty(
85249 ol.Feature.prototype,
85250 'changed',
85251 ol.Feature.prototype.changed);
85252
85253goog.exportProperty(
85254 ol.Feature.prototype,
85255 'dispatchEvent',
85256 ol.Feature.prototype.dispatchEvent);
85257
85258goog.exportProperty(
85259 ol.Feature.prototype,
85260 'getRevision',
85261 ol.Feature.prototype.getRevision);
85262
85263goog.exportProperty(
85264 ol.Feature.prototype,
85265 'on',
85266 ol.Feature.prototype.on);
85267
85268goog.exportProperty(
85269 ol.Feature.prototype,
85270 'once',
85271 ol.Feature.prototype.once);
85272
85273goog.exportProperty(
85274 ol.Feature.prototype,
85275 'un',
85276 ol.Feature.prototype.un);
85277
85278goog.exportProperty(
85279 ol.Geolocation.prototype,
85280 'get',
85281 ol.Geolocation.prototype.get);
85282
85283goog.exportProperty(
85284 ol.Geolocation.prototype,
85285 'getKeys',
85286 ol.Geolocation.prototype.getKeys);
85287
85288goog.exportProperty(
85289 ol.Geolocation.prototype,
85290 'getProperties',
85291 ol.Geolocation.prototype.getProperties);
85292
85293goog.exportProperty(
85294 ol.Geolocation.prototype,
85295 'set',
85296 ol.Geolocation.prototype.set);
85297
85298goog.exportProperty(
85299 ol.Geolocation.prototype,
85300 'setProperties',
85301 ol.Geolocation.prototype.setProperties);
85302
85303goog.exportProperty(
85304 ol.Geolocation.prototype,
85305 'unset',
85306 ol.Geolocation.prototype.unset);
85307
85308goog.exportProperty(
85309 ol.Geolocation.prototype,
85310 'changed',
85311 ol.Geolocation.prototype.changed);
85312
85313goog.exportProperty(
85314 ol.Geolocation.prototype,
85315 'dispatchEvent',
85316 ol.Geolocation.prototype.dispatchEvent);
85317
85318goog.exportProperty(
85319 ol.Geolocation.prototype,
85320 'getRevision',
85321 ol.Geolocation.prototype.getRevision);
85322
85323goog.exportProperty(
85324 ol.Geolocation.prototype,
85325 'on',
85326 ol.Geolocation.prototype.on);
85327
85328goog.exportProperty(
85329 ol.Geolocation.prototype,
85330 'once',
85331 ol.Geolocation.prototype.once);
85332
85333goog.exportProperty(
85334 ol.Geolocation.prototype,
85335 'un',
85336 ol.Geolocation.prototype.un);
85337
85338goog.exportProperty(
85339 ol.ImageTile.prototype,
85340 'getTileCoord',
85341 ol.ImageTile.prototype.getTileCoord);
85342
85343goog.exportProperty(
85344 ol.ImageTile.prototype,
85345 'load',
85346 ol.ImageTile.prototype.load);
85347
85348goog.exportProperty(
85349 ol.Map.prototype,
85350 'get',
85351 ol.Map.prototype.get);
85352
85353goog.exportProperty(
85354 ol.Map.prototype,
85355 'getKeys',
85356 ol.Map.prototype.getKeys);
85357
85358goog.exportProperty(
85359 ol.Map.prototype,
85360 'getProperties',
85361 ol.Map.prototype.getProperties);
85362
85363goog.exportProperty(
85364 ol.Map.prototype,
85365 'set',
85366 ol.Map.prototype.set);
85367
85368goog.exportProperty(
85369 ol.Map.prototype,
85370 'setProperties',
85371 ol.Map.prototype.setProperties);
85372
85373goog.exportProperty(
85374 ol.Map.prototype,
85375 'unset',
85376 ol.Map.prototype.unset);
85377
85378goog.exportProperty(
85379 ol.Map.prototype,
85380 'changed',
85381 ol.Map.prototype.changed);
85382
85383goog.exportProperty(
85384 ol.Map.prototype,
85385 'dispatchEvent',
85386 ol.Map.prototype.dispatchEvent);
85387
85388goog.exportProperty(
85389 ol.Map.prototype,
85390 'getRevision',
85391 ol.Map.prototype.getRevision);
85392
85393goog.exportProperty(
85394 ol.Map.prototype,
85395 'on',
85396 ol.Map.prototype.on);
85397
85398goog.exportProperty(
85399 ol.Map.prototype,
85400 'once',
85401 ol.Map.prototype.once);
85402
85403goog.exportProperty(
85404 ol.Map.prototype,
85405 'un',
85406 ol.Map.prototype.un);
85407
85408goog.exportProperty(
85409 ol.MapEvent.prototype,
85410 'type',
85411 ol.MapEvent.prototype.type);
85412
85413goog.exportProperty(
85414 ol.MapEvent.prototype,
85415 'target',
85416 ol.MapEvent.prototype.target);
85417
85418goog.exportProperty(
85419 ol.MapEvent.prototype,
85420 'preventDefault',
85421 ol.MapEvent.prototype.preventDefault);
85422
85423goog.exportProperty(
85424 ol.MapEvent.prototype,
85425 'stopPropagation',
85426 ol.MapEvent.prototype.stopPropagation);
85427
85428goog.exportProperty(
85429 ol.MapBrowserEvent.prototype,
85430 'map',
85431 ol.MapBrowserEvent.prototype.map);
85432
85433goog.exportProperty(
85434 ol.MapBrowserEvent.prototype,
85435 'frameState',
85436 ol.MapBrowserEvent.prototype.frameState);
85437
85438goog.exportProperty(
85439 ol.MapBrowserEvent.prototype,
85440 'type',
85441 ol.MapBrowserEvent.prototype.type);
85442
85443goog.exportProperty(
85444 ol.MapBrowserEvent.prototype,
85445 'target',
85446 ol.MapBrowserEvent.prototype.target);
85447
85448goog.exportProperty(
85449 ol.MapBrowserEvent.prototype,
85450 'preventDefault',
85451 ol.MapBrowserEvent.prototype.preventDefault);
85452
85453goog.exportProperty(
85454 ol.MapBrowserEvent.prototype,
85455 'stopPropagation',
85456 ol.MapBrowserEvent.prototype.stopPropagation);
85457
85458goog.exportProperty(
85459 ol.MapBrowserPointerEvent.prototype,
85460 'originalEvent',
85461 ol.MapBrowserPointerEvent.prototype.originalEvent);
85462
85463goog.exportProperty(
85464 ol.MapBrowserPointerEvent.prototype,
85465 'pixel',
85466 ol.MapBrowserPointerEvent.prototype.pixel);
85467
85468goog.exportProperty(
85469 ol.MapBrowserPointerEvent.prototype,
85470 'coordinate',
85471 ol.MapBrowserPointerEvent.prototype.coordinate);
85472
85473goog.exportProperty(
85474 ol.MapBrowserPointerEvent.prototype,
85475 'dragging',
85476 ol.MapBrowserPointerEvent.prototype.dragging);
85477
85478goog.exportProperty(
85479 ol.MapBrowserPointerEvent.prototype,
85480 'preventDefault',
85481 ol.MapBrowserPointerEvent.prototype.preventDefault);
85482
85483goog.exportProperty(
85484 ol.MapBrowserPointerEvent.prototype,
85485 'stopPropagation',
85486 ol.MapBrowserPointerEvent.prototype.stopPropagation);
85487
85488goog.exportProperty(
85489 ol.MapBrowserPointerEvent.prototype,
85490 'map',
85491 ol.MapBrowserPointerEvent.prototype.map);
85492
85493goog.exportProperty(
85494 ol.MapBrowserPointerEvent.prototype,
85495 'frameState',
85496 ol.MapBrowserPointerEvent.prototype.frameState);
85497
85498goog.exportProperty(
85499 ol.MapBrowserPointerEvent.prototype,
85500 'type',
85501 ol.MapBrowserPointerEvent.prototype.type);
85502
85503goog.exportProperty(
85504 ol.MapBrowserPointerEvent.prototype,
85505 'target',
85506 ol.MapBrowserPointerEvent.prototype.target);
85507
85508goog.exportProperty(
85509 ol.Object.Event.prototype,
85510 'type',
85511 ol.Object.Event.prototype.type);
85512
85513goog.exportProperty(
85514 ol.Object.Event.prototype,
85515 'target',
85516 ol.Object.Event.prototype.target);
85517
85518goog.exportProperty(
85519 ol.Object.Event.prototype,
85520 'preventDefault',
85521 ol.Object.Event.prototype.preventDefault);
85522
85523goog.exportProperty(
85524 ol.Object.Event.prototype,
85525 'stopPropagation',
85526 ol.Object.Event.prototype.stopPropagation);
85527
85528goog.exportProperty(
85529 ol.Overlay.prototype,
85530 'get',
85531 ol.Overlay.prototype.get);
85532
85533goog.exportProperty(
85534 ol.Overlay.prototype,
85535 'getKeys',
85536 ol.Overlay.prototype.getKeys);
85537
85538goog.exportProperty(
85539 ol.Overlay.prototype,
85540 'getProperties',
85541 ol.Overlay.prototype.getProperties);
85542
85543goog.exportProperty(
85544 ol.Overlay.prototype,
85545 'set',
85546 ol.Overlay.prototype.set);
85547
85548goog.exportProperty(
85549 ol.Overlay.prototype,
85550 'setProperties',
85551 ol.Overlay.prototype.setProperties);
85552
85553goog.exportProperty(
85554 ol.Overlay.prototype,
85555 'unset',
85556 ol.Overlay.prototype.unset);
85557
85558goog.exportProperty(
85559 ol.Overlay.prototype,
85560 'changed',
85561 ol.Overlay.prototype.changed);
85562
85563goog.exportProperty(
85564 ol.Overlay.prototype,
85565 'dispatchEvent',
85566 ol.Overlay.prototype.dispatchEvent);
85567
85568goog.exportProperty(
85569 ol.Overlay.prototype,
85570 'getRevision',
85571 ol.Overlay.prototype.getRevision);
85572
85573goog.exportProperty(
85574 ol.Overlay.prototype,
85575 'on',
85576 ol.Overlay.prototype.on);
85577
85578goog.exportProperty(
85579 ol.Overlay.prototype,
85580 'once',
85581 ol.Overlay.prototype.once);
85582
85583goog.exportProperty(
85584 ol.Overlay.prototype,
85585 'un',
85586 ol.Overlay.prototype.un);
85587
85588goog.exportProperty(
85589 ol.VectorImageTile.prototype,
85590 'getTileCoord',
85591 ol.VectorImageTile.prototype.getTileCoord);
85592
85593goog.exportProperty(
85594 ol.VectorImageTile.prototype,
85595 'load',
85596 ol.VectorImageTile.prototype.load);
85597
85598goog.exportProperty(
85599 ol.VectorTile.prototype,
85600 'getTileCoord',
85601 ol.VectorTile.prototype.getTileCoord);
85602
85603goog.exportProperty(
85604 ol.VectorTile.prototype,
85605 'load',
85606 ol.VectorTile.prototype.load);
85607
85608goog.exportProperty(
85609 ol.View.prototype,
85610 'get',
85611 ol.View.prototype.get);
85612
85613goog.exportProperty(
85614 ol.View.prototype,
85615 'getKeys',
85616 ol.View.prototype.getKeys);
85617
85618goog.exportProperty(
85619 ol.View.prototype,
85620 'getProperties',
85621 ol.View.prototype.getProperties);
85622
85623goog.exportProperty(
85624 ol.View.prototype,
85625 'set',
85626 ol.View.prototype.set);
85627
85628goog.exportProperty(
85629 ol.View.prototype,
85630 'setProperties',
85631 ol.View.prototype.setProperties);
85632
85633goog.exportProperty(
85634 ol.View.prototype,
85635 'unset',
85636 ol.View.prototype.unset);
85637
85638goog.exportProperty(
85639 ol.View.prototype,
85640 'changed',
85641 ol.View.prototype.changed);
85642
85643goog.exportProperty(
85644 ol.View.prototype,
85645 'dispatchEvent',
85646 ol.View.prototype.dispatchEvent);
85647
85648goog.exportProperty(
85649 ol.View.prototype,
85650 'getRevision',
85651 ol.View.prototype.getRevision);
85652
85653goog.exportProperty(
85654 ol.View.prototype,
85655 'on',
85656 ol.View.prototype.on);
85657
85658goog.exportProperty(
85659 ol.View.prototype,
85660 'once',
85661 ol.View.prototype.once);
85662
85663goog.exportProperty(
85664 ol.View.prototype,
85665 'un',
85666 ol.View.prototype.un);
85667
85668goog.exportProperty(
85669 ol.tilegrid.WMTS.prototype,
85670 'forEachTileCoord',
85671 ol.tilegrid.WMTS.prototype.forEachTileCoord);
85672
85673goog.exportProperty(
85674 ol.tilegrid.WMTS.prototype,
85675 'getMaxZoom',
85676 ol.tilegrid.WMTS.prototype.getMaxZoom);
85677
85678goog.exportProperty(
85679 ol.tilegrid.WMTS.prototype,
85680 'getMinZoom',
85681 ol.tilegrid.WMTS.prototype.getMinZoom);
85682
85683goog.exportProperty(
85684 ol.tilegrid.WMTS.prototype,
85685 'getOrigin',
85686 ol.tilegrid.WMTS.prototype.getOrigin);
85687
85688goog.exportProperty(
85689 ol.tilegrid.WMTS.prototype,
85690 'getResolution',
85691 ol.tilegrid.WMTS.prototype.getResolution);
85692
85693goog.exportProperty(
85694 ol.tilegrid.WMTS.prototype,
85695 'getResolutions',
85696 ol.tilegrid.WMTS.prototype.getResolutions);
85697
85698goog.exportProperty(
85699 ol.tilegrid.WMTS.prototype,
85700 'getTileCoordExtent',
85701 ol.tilegrid.WMTS.prototype.getTileCoordExtent);
85702
85703goog.exportProperty(
85704 ol.tilegrid.WMTS.prototype,
85705 'getTileCoordForCoordAndResolution',
85706 ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndResolution);
85707
85708goog.exportProperty(
85709 ol.tilegrid.WMTS.prototype,
85710 'getTileCoordForCoordAndZ',
85711 ol.tilegrid.WMTS.prototype.getTileCoordForCoordAndZ);
85712
85713goog.exportProperty(
85714 ol.tilegrid.WMTS.prototype,
85715 'getTileSize',
85716 ol.tilegrid.WMTS.prototype.getTileSize);
85717
85718goog.exportProperty(
85719 ol.tilegrid.WMTS.prototype,
85720 'getZForResolution',
85721 ol.tilegrid.WMTS.prototype.getZForResolution);
85722
85723goog.exportProperty(
85724 ol.style.RegularShape.prototype,
85725 'getOpacity',
85726 ol.style.RegularShape.prototype.getOpacity);
85727
85728goog.exportProperty(
85729 ol.style.RegularShape.prototype,
85730 'getRotateWithView',
85731 ol.style.RegularShape.prototype.getRotateWithView);
85732
85733goog.exportProperty(
85734 ol.style.RegularShape.prototype,
85735 'getRotation',
85736 ol.style.RegularShape.prototype.getRotation);
85737
85738goog.exportProperty(
85739 ol.style.RegularShape.prototype,
85740 'getScale',
85741 ol.style.RegularShape.prototype.getScale);
85742
85743goog.exportProperty(
85744 ol.style.RegularShape.prototype,
85745 'getSnapToPixel',
85746 ol.style.RegularShape.prototype.getSnapToPixel);
85747
85748goog.exportProperty(
85749 ol.style.RegularShape.prototype,
85750 'setOpacity',
85751 ol.style.RegularShape.prototype.setOpacity);
85752
85753goog.exportProperty(
85754 ol.style.RegularShape.prototype,
85755 'setRotation',
85756 ol.style.RegularShape.prototype.setRotation);
85757
85758goog.exportProperty(
85759 ol.style.RegularShape.prototype,
85760 'setScale',
85761 ol.style.RegularShape.prototype.setScale);
85762
85763goog.exportProperty(
85764 ol.style.Circle.prototype,
85765 'clone',
85766 ol.style.Circle.prototype.clone);
85767
85768goog.exportProperty(
85769 ol.style.Circle.prototype,
85770 'getAngle',
85771 ol.style.Circle.prototype.getAngle);
85772
85773goog.exportProperty(
85774 ol.style.Circle.prototype,
85775 'getFill',
85776 ol.style.Circle.prototype.getFill);
85777
85778goog.exportProperty(
85779 ol.style.Circle.prototype,
85780 'getPoints',
85781 ol.style.Circle.prototype.getPoints);
85782
85783goog.exportProperty(
85784 ol.style.Circle.prototype,
85785 'getRadius',
85786 ol.style.Circle.prototype.getRadius);
85787
85788goog.exportProperty(
85789 ol.style.Circle.prototype,
85790 'getRadius2',
85791 ol.style.Circle.prototype.getRadius2);
85792
85793goog.exportProperty(
85794 ol.style.Circle.prototype,
85795 'getStroke',
85796 ol.style.Circle.prototype.getStroke);
85797
85798goog.exportProperty(
85799 ol.style.Circle.prototype,
85800 'getOpacity',
85801 ol.style.Circle.prototype.getOpacity);
85802
85803goog.exportProperty(
85804 ol.style.Circle.prototype,
85805 'getRotateWithView',
85806 ol.style.Circle.prototype.getRotateWithView);
85807
85808goog.exportProperty(
85809 ol.style.Circle.prototype,
85810 'getRotation',
85811 ol.style.Circle.prototype.getRotation);
85812
85813goog.exportProperty(
85814 ol.style.Circle.prototype,
85815 'getScale',
85816 ol.style.Circle.prototype.getScale);
85817
85818goog.exportProperty(
85819 ol.style.Circle.prototype,
85820 'getSnapToPixel',
85821 ol.style.Circle.prototype.getSnapToPixel);
85822
85823goog.exportProperty(
85824 ol.style.Circle.prototype,
85825 'setOpacity',
85826 ol.style.Circle.prototype.setOpacity);
85827
85828goog.exportProperty(
85829 ol.style.Circle.prototype,
85830 'setRotation',
85831 ol.style.Circle.prototype.setRotation);
85832
85833goog.exportProperty(
85834 ol.style.Circle.prototype,
85835 'setScale',
85836 ol.style.Circle.prototype.setScale);
85837
85838goog.exportProperty(
85839 ol.style.Icon.prototype,
85840 'getOpacity',
85841 ol.style.Icon.prototype.getOpacity);
85842
85843goog.exportProperty(
85844 ol.style.Icon.prototype,
85845 'getRotateWithView',
85846 ol.style.Icon.prototype.getRotateWithView);
85847
85848goog.exportProperty(
85849 ol.style.Icon.prototype,
85850 'getRotation',
85851 ol.style.Icon.prototype.getRotation);
85852
85853goog.exportProperty(
85854 ol.style.Icon.prototype,
85855 'getScale',
85856 ol.style.Icon.prototype.getScale);
85857
85858goog.exportProperty(
85859 ol.style.Icon.prototype,
85860 'getSnapToPixel',
85861 ol.style.Icon.prototype.getSnapToPixel);
85862
85863goog.exportProperty(
85864 ol.style.Icon.prototype,
85865 'setOpacity',
85866 ol.style.Icon.prototype.setOpacity);
85867
85868goog.exportProperty(
85869 ol.style.Icon.prototype,
85870 'setRotation',
85871 ol.style.Icon.prototype.setRotation);
85872
85873goog.exportProperty(
85874 ol.style.Icon.prototype,
85875 'setScale',
85876 ol.style.Icon.prototype.setScale);
85877
85878goog.exportProperty(
85879 ol.source.Source.prototype,
85880 'get',
85881 ol.source.Source.prototype.get);
85882
85883goog.exportProperty(
85884 ol.source.Source.prototype,
85885 'getKeys',
85886 ol.source.Source.prototype.getKeys);
85887
85888goog.exportProperty(
85889 ol.source.Source.prototype,
85890 'getProperties',
85891 ol.source.Source.prototype.getProperties);
85892
85893goog.exportProperty(
85894 ol.source.Source.prototype,
85895 'set',
85896 ol.source.Source.prototype.set);
85897
85898goog.exportProperty(
85899 ol.source.Source.prototype,
85900 'setProperties',
85901 ol.source.Source.prototype.setProperties);
85902
85903goog.exportProperty(
85904 ol.source.Source.prototype,
85905 'unset',
85906 ol.source.Source.prototype.unset);
85907
85908goog.exportProperty(
85909 ol.source.Source.prototype,
85910 'changed',
85911 ol.source.Source.prototype.changed);
85912
85913goog.exportProperty(
85914 ol.source.Source.prototype,
85915 'dispatchEvent',
85916 ol.source.Source.prototype.dispatchEvent);
85917
85918goog.exportProperty(
85919 ol.source.Source.prototype,
85920 'getRevision',
85921 ol.source.Source.prototype.getRevision);
85922
85923goog.exportProperty(
85924 ol.source.Source.prototype,
85925 'on',
85926 ol.source.Source.prototype.on);
85927
85928goog.exportProperty(
85929 ol.source.Source.prototype,
85930 'once',
85931 ol.source.Source.prototype.once);
85932
85933goog.exportProperty(
85934 ol.source.Source.prototype,
85935 'un',
85936 ol.source.Source.prototype.un);
85937
85938goog.exportProperty(
85939 ol.source.Tile.prototype,
85940 'getAttributions',
85941 ol.source.Tile.prototype.getAttributions);
85942
85943goog.exportProperty(
85944 ol.source.Tile.prototype,
85945 'getLogo',
85946 ol.source.Tile.prototype.getLogo);
85947
85948goog.exportProperty(
85949 ol.source.Tile.prototype,
85950 'getProjection',
85951 ol.source.Tile.prototype.getProjection);
85952
85953goog.exportProperty(
85954 ol.source.Tile.prototype,
85955 'getState',
85956 ol.source.Tile.prototype.getState);
85957
85958goog.exportProperty(
85959 ol.source.Tile.prototype,
85960 'refresh',
85961 ol.source.Tile.prototype.refresh);
85962
85963goog.exportProperty(
85964 ol.source.Tile.prototype,
85965 'setAttributions',
85966 ol.source.Tile.prototype.setAttributions);
85967
85968goog.exportProperty(
85969 ol.source.Tile.prototype,
85970 'get',
85971 ol.source.Tile.prototype.get);
85972
85973goog.exportProperty(
85974 ol.source.Tile.prototype,
85975 'getKeys',
85976 ol.source.Tile.prototype.getKeys);
85977
85978goog.exportProperty(
85979 ol.source.Tile.prototype,
85980 'getProperties',
85981 ol.source.Tile.prototype.getProperties);
85982
85983goog.exportProperty(
85984 ol.source.Tile.prototype,
85985 'set',
85986 ol.source.Tile.prototype.set);
85987
85988goog.exportProperty(
85989 ol.source.Tile.prototype,
85990 'setProperties',
85991 ol.source.Tile.prototype.setProperties);
85992
85993goog.exportProperty(
85994 ol.source.Tile.prototype,
85995 'unset',
85996 ol.source.Tile.prototype.unset);
85997
85998goog.exportProperty(
85999 ol.source.Tile.prototype,
86000 'changed',
86001 ol.source.Tile.prototype.changed);
86002
86003goog.exportProperty(
86004 ol.source.Tile.prototype,
86005 'dispatchEvent',
86006 ol.source.Tile.prototype.dispatchEvent);
86007
86008goog.exportProperty(
86009 ol.source.Tile.prototype,
86010 'getRevision',
86011 ol.source.Tile.prototype.getRevision);
86012
86013goog.exportProperty(
86014 ol.source.Tile.prototype,
86015 'on',
86016 ol.source.Tile.prototype.on);
86017
86018goog.exportProperty(
86019 ol.source.Tile.prototype,
86020 'once',
86021 ol.source.Tile.prototype.once);
86022
86023goog.exportProperty(
86024 ol.source.Tile.prototype,
86025 'un',
86026 ol.source.Tile.prototype.un);
86027
86028goog.exportProperty(
86029 ol.source.UrlTile.prototype,
86030 'getTileGrid',
86031 ol.source.UrlTile.prototype.getTileGrid);
86032
86033goog.exportProperty(
86034 ol.source.UrlTile.prototype,
86035 'refresh',
86036 ol.source.UrlTile.prototype.refresh);
86037
86038goog.exportProperty(
86039 ol.source.UrlTile.prototype,
86040 'getAttributions',
86041 ol.source.UrlTile.prototype.getAttributions);
86042
86043goog.exportProperty(
86044 ol.source.UrlTile.prototype,
86045 'getLogo',
86046 ol.source.UrlTile.prototype.getLogo);
86047
86048goog.exportProperty(
86049 ol.source.UrlTile.prototype,
86050 'getProjection',
86051 ol.source.UrlTile.prototype.getProjection);
86052
86053goog.exportProperty(
86054 ol.source.UrlTile.prototype,
86055 'getState',
86056 ol.source.UrlTile.prototype.getState);
86057
86058goog.exportProperty(
86059 ol.source.UrlTile.prototype,
86060 'setAttributions',
86061 ol.source.UrlTile.prototype.setAttributions);
86062
86063goog.exportProperty(
86064 ol.source.UrlTile.prototype,
86065 'get',
86066 ol.source.UrlTile.prototype.get);
86067
86068goog.exportProperty(
86069 ol.source.UrlTile.prototype,
86070 'getKeys',
86071 ol.source.UrlTile.prototype.getKeys);
86072
86073goog.exportProperty(
86074 ol.source.UrlTile.prototype,
86075 'getProperties',
86076 ol.source.UrlTile.prototype.getProperties);
86077
86078goog.exportProperty(
86079 ol.source.UrlTile.prototype,
86080 'set',
86081 ol.source.UrlTile.prototype.set);
86082
86083goog.exportProperty(
86084 ol.source.UrlTile.prototype,
86085 'setProperties',
86086 ol.source.UrlTile.prototype.setProperties);
86087
86088goog.exportProperty(
86089 ol.source.UrlTile.prototype,
86090 'unset',
86091 ol.source.UrlTile.prototype.unset);
86092
86093goog.exportProperty(
86094 ol.source.UrlTile.prototype,
86095 'changed',
86096 ol.source.UrlTile.prototype.changed);
86097
86098goog.exportProperty(
86099 ol.source.UrlTile.prototype,
86100 'dispatchEvent',
86101 ol.source.UrlTile.prototype.dispatchEvent);
86102
86103goog.exportProperty(
86104 ol.source.UrlTile.prototype,
86105 'getRevision',
86106 ol.source.UrlTile.prototype.getRevision);
86107
86108goog.exportProperty(
86109 ol.source.UrlTile.prototype,
86110 'on',
86111 ol.source.UrlTile.prototype.on);
86112
86113goog.exportProperty(
86114 ol.source.UrlTile.prototype,
86115 'once',
86116 ol.source.UrlTile.prototype.once);
86117
86118goog.exportProperty(
86119 ol.source.UrlTile.prototype,
86120 'un',
86121 ol.source.UrlTile.prototype.un);
86122
86123goog.exportProperty(
86124 ol.source.TileImage.prototype,
86125 'getTileLoadFunction',
86126 ol.source.TileImage.prototype.getTileLoadFunction);
86127
86128goog.exportProperty(
86129 ol.source.TileImage.prototype,
86130 'getTileUrlFunction',
86131 ol.source.TileImage.prototype.getTileUrlFunction);
86132
86133goog.exportProperty(
86134 ol.source.TileImage.prototype,
86135 'getUrls',
86136 ol.source.TileImage.prototype.getUrls);
86137
86138goog.exportProperty(
86139 ol.source.TileImage.prototype,
86140 'setTileLoadFunction',
86141 ol.source.TileImage.prototype.setTileLoadFunction);
86142
86143goog.exportProperty(
86144 ol.source.TileImage.prototype,
86145 'setTileUrlFunction',
86146 ol.source.TileImage.prototype.setTileUrlFunction);
86147
86148goog.exportProperty(
86149 ol.source.TileImage.prototype,
86150 'setUrl',
86151 ol.source.TileImage.prototype.setUrl);
86152
86153goog.exportProperty(
86154 ol.source.TileImage.prototype,
86155 'setUrls',
86156 ol.source.TileImage.prototype.setUrls);
86157
86158goog.exportProperty(
86159 ol.source.TileImage.prototype,
86160 'getTileGrid',
86161 ol.source.TileImage.prototype.getTileGrid);
86162
86163goog.exportProperty(
86164 ol.source.TileImage.prototype,
86165 'refresh',
86166 ol.source.TileImage.prototype.refresh);
86167
86168goog.exportProperty(
86169 ol.source.TileImage.prototype,
86170 'getAttributions',
86171 ol.source.TileImage.prototype.getAttributions);
86172
86173goog.exportProperty(
86174 ol.source.TileImage.prototype,
86175 'getLogo',
86176 ol.source.TileImage.prototype.getLogo);
86177
86178goog.exportProperty(
86179 ol.source.TileImage.prototype,
86180 'getProjection',
86181 ol.source.TileImage.prototype.getProjection);
86182
86183goog.exportProperty(
86184 ol.source.TileImage.prototype,
86185 'getState',
86186 ol.source.TileImage.prototype.getState);
86187
86188goog.exportProperty(
86189 ol.source.TileImage.prototype,
86190 'setAttributions',
86191 ol.source.TileImage.prototype.setAttributions);
86192
86193goog.exportProperty(
86194 ol.source.TileImage.prototype,
86195 'get',
86196 ol.source.TileImage.prototype.get);
86197
86198goog.exportProperty(
86199 ol.source.TileImage.prototype,
86200 'getKeys',
86201 ol.source.TileImage.prototype.getKeys);
86202
86203goog.exportProperty(
86204 ol.source.TileImage.prototype,
86205 'getProperties',
86206 ol.source.TileImage.prototype.getProperties);
86207
86208goog.exportProperty(
86209 ol.source.TileImage.prototype,
86210 'set',
86211 ol.source.TileImage.prototype.set);
86212
86213goog.exportProperty(
86214 ol.source.TileImage.prototype,
86215 'setProperties',
86216 ol.source.TileImage.prototype.setProperties);
86217
86218goog.exportProperty(
86219 ol.source.TileImage.prototype,
86220 'unset',
86221 ol.source.TileImage.prototype.unset);
86222
86223goog.exportProperty(
86224 ol.source.TileImage.prototype,
86225 'changed',
86226 ol.source.TileImage.prototype.changed);
86227
86228goog.exportProperty(
86229 ol.source.TileImage.prototype,
86230 'dispatchEvent',
86231 ol.source.TileImage.prototype.dispatchEvent);
86232
86233goog.exportProperty(
86234 ol.source.TileImage.prototype,
86235 'getRevision',
86236 ol.source.TileImage.prototype.getRevision);
86237
86238goog.exportProperty(
86239 ol.source.TileImage.prototype,
86240 'on',
86241 ol.source.TileImage.prototype.on);
86242
86243goog.exportProperty(
86244 ol.source.TileImage.prototype,
86245 'once',
86246 ol.source.TileImage.prototype.once);
86247
86248goog.exportProperty(
86249 ol.source.TileImage.prototype,
86250 'un',
86251 ol.source.TileImage.prototype.un);
86252
86253goog.exportProperty(
86254 ol.source.BingMaps.prototype,
86255 'setRenderReprojectionEdges',
86256 ol.source.BingMaps.prototype.setRenderReprojectionEdges);
86257
86258goog.exportProperty(
86259 ol.source.BingMaps.prototype,
86260 'setTileGridForProjection',
86261 ol.source.BingMaps.prototype.setTileGridForProjection);
86262
86263goog.exportProperty(
86264 ol.source.BingMaps.prototype,
86265 'getTileLoadFunction',
86266 ol.source.BingMaps.prototype.getTileLoadFunction);
86267
86268goog.exportProperty(
86269 ol.source.BingMaps.prototype,
86270 'getTileUrlFunction',
86271 ol.source.BingMaps.prototype.getTileUrlFunction);
86272
86273goog.exportProperty(
86274 ol.source.BingMaps.prototype,
86275 'getUrls',
86276 ol.source.BingMaps.prototype.getUrls);
86277
86278goog.exportProperty(
86279 ol.source.BingMaps.prototype,
86280 'setTileLoadFunction',
86281 ol.source.BingMaps.prototype.setTileLoadFunction);
86282
86283goog.exportProperty(
86284 ol.source.BingMaps.prototype,
86285 'setTileUrlFunction',
86286 ol.source.BingMaps.prototype.setTileUrlFunction);
86287
86288goog.exportProperty(
86289 ol.source.BingMaps.prototype,
86290 'setUrl',
86291 ol.source.BingMaps.prototype.setUrl);
86292
86293goog.exportProperty(
86294 ol.source.BingMaps.prototype,
86295 'setUrls',
86296 ol.source.BingMaps.prototype.setUrls);
86297
86298goog.exportProperty(
86299 ol.source.BingMaps.prototype,
86300 'getTileGrid',
86301 ol.source.BingMaps.prototype.getTileGrid);
86302
86303goog.exportProperty(
86304 ol.source.BingMaps.prototype,
86305 'refresh',
86306 ol.source.BingMaps.prototype.refresh);
86307
86308goog.exportProperty(
86309 ol.source.BingMaps.prototype,
86310 'getAttributions',
86311 ol.source.BingMaps.prototype.getAttributions);
86312
86313goog.exportProperty(
86314 ol.source.BingMaps.prototype,
86315 'getLogo',
86316 ol.source.BingMaps.prototype.getLogo);
86317
86318goog.exportProperty(
86319 ol.source.BingMaps.prototype,
86320 'getProjection',
86321 ol.source.BingMaps.prototype.getProjection);
86322
86323goog.exportProperty(
86324 ol.source.BingMaps.prototype,
86325 'getState',
86326 ol.source.BingMaps.prototype.getState);
86327
86328goog.exportProperty(
86329 ol.source.BingMaps.prototype,
86330 'setAttributions',
86331 ol.source.BingMaps.prototype.setAttributions);
86332
86333goog.exportProperty(
86334 ol.source.BingMaps.prototype,
86335 'get',
86336 ol.source.BingMaps.prototype.get);
86337
86338goog.exportProperty(
86339 ol.source.BingMaps.prototype,
86340 'getKeys',
86341 ol.source.BingMaps.prototype.getKeys);
86342
86343goog.exportProperty(
86344 ol.source.BingMaps.prototype,
86345 'getProperties',
86346 ol.source.BingMaps.prototype.getProperties);
86347
86348goog.exportProperty(
86349 ol.source.BingMaps.prototype,
86350 'set',
86351 ol.source.BingMaps.prototype.set);
86352
86353goog.exportProperty(
86354 ol.source.BingMaps.prototype,
86355 'setProperties',
86356 ol.source.BingMaps.prototype.setProperties);
86357
86358goog.exportProperty(
86359 ol.source.BingMaps.prototype,
86360 'unset',
86361 ol.source.BingMaps.prototype.unset);
86362
86363goog.exportProperty(
86364 ol.source.BingMaps.prototype,
86365 'changed',
86366 ol.source.BingMaps.prototype.changed);
86367
86368goog.exportProperty(
86369 ol.source.BingMaps.prototype,
86370 'dispatchEvent',
86371 ol.source.BingMaps.prototype.dispatchEvent);
86372
86373goog.exportProperty(
86374 ol.source.BingMaps.prototype,
86375 'getRevision',
86376 ol.source.BingMaps.prototype.getRevision);
86377
86378goog.exportProperty(
86379 ol.source.BingMaps.prototype,
86380 'on',
86381 ol.source.BingMaps.prototype.on);
86382
86383goog.exportProperty(
86384 ol.source.BingMaps.prototype,
86385 'once',
86386 ol.source.BingMaps.prototype.once);
86387
86388goog.exportProperty(
86389 ol.source.BingMaps.prototype,
86390 'un',
86391 ol.source.BingMaps.prototype.un);
86392
86393goog.exportProperty(
86394 ol.source.XYZ.prototype,
86395 'setRenderReprojectionEdges',
86396 ol.source.XYZ.prototype.setRenderReprojectionEdges);
86397
86398goog.exportProperty(
86399 ol.source.XYZ.prototype,
86400 'setTileGridForProjection',
86401 ol.source.XYZ.prototype.setTileGridForProjection);
86402
86403goog.exportProperty(
86404 ol.source.XYZ.prototype,
86405 'getTileLoadFunction',
86406 ol.source.XYZ.prototype.getTileLoadFunction);
86407
86408goog.exportProperty(
86409 ol.source.XYZ.prototype,
86410 'getTileUrlFunction',
86411 ol.source.XYZ.prototype.getTileUrlFunction);
86412
86413goog.exportProperty(
86414 ol.source.XYZ.prototype,
86415 'getUrls',
86416 ol.source.XYZ.prototype.getUrls);
86417
86418goog.exportProperty(
86419 ol.source.XYZ.prototype,
86420 'setTileLoadFunction',
86421 ol.source.XYZ.prototype.setTileLoadFunction);
86422
86423goog.exportProperty(
86424 ol.source.XYZ.prototype,
86425 'setTileUrlFunction',
86426 ol.source.XYZ.prototype.setTileUrlFunction);
86427
86428goog.exportProperty(
86429 ol.source.XYZ.prototype,
86430 'setUrl',
86431 ol.source.XYZ.prototype.setUrl);
86432
86433goog.exportProperty(
86434 ol.source.XYZ.prototype,
86435 'setUrls',
86436 ol.source.XYZ.prototype.setUrls);
86437
86438goog.exportProperty(
86439 ol.source.XYZ.prototype,
86440 'getTileGrid',
86441 ol.source.XYZ.prototype.getTileGrid);
86442
86443goog.exportProperty(
86444 ol.source.XYZ.prototype,
86445 'refresh',
86446 ol.source.XYZ.prototype.refresh);
86447
86448goog.exportProperty(
86449 ol.source.XYZ.prototype,
86450 'getAttributions',
86451 ol.source.XYZ.prototype.getAttributions);
86452
86453goog.exportProperty(
86454 ol.source.XYZ.prototype,
86455 'getLogo',
86456 ol.source.XYZ.prototype.getLogo);
86457
86458goog.exportProperty(
86459 ol.source.XYZ.prototype,
86460 'getProjection',
86461 ol.source.XYZ.prototype.getProjection);
86462
86463goog.exportProperty(
86464 ol.source.XYZ.prototype,
86465 'getState',
86466 ol.source.XYZ.prototype.getState);
86467
86468goog.exportProperty(
86469 ol.source.XYZ.prototype,
86470 'setAttributions',
86471 ol.source.XYZ.prototype.setAttributions);
86472
86473goog.exportProperty(
86474 ol.source.XYZ.prototype,
86475 'get',
86476 ol.source.XYZ.prototype.get);
86477
86478goog.exportProperty(
86479 ol.source.XYZ.prototype,
86480 'getKeys',
86481 ol.source.XYZ.prototype.getKeys);
86482
86483goog.exportProperty(
86484 ol.source.XYZ.prototype,
86485 'getProperties',
86486 ol.source.XYZ.prototype.getProperties);
86487
86488goog.exportProperty(
86489 ol.source.XYZ.prototype,
86490 'set',
86491 ol.source.XYZ.prototype.set);
86492
86493goog.exportProperty(
86494 ol.source.XYZ.prototype,
86495 'setProperties',
86496 ol.source.XYZ.prototype.setProperties);
86497
86498goog.exportProperty(
86499 ol.source.XYZ.prototype,
86500 'unset',
86501 ol.source.XYZ.prototype.unset);
86502
86503goog.exportProperty(
86504 ol.source.XYZ.prototype,
86505 'changed',
86506 ol.source.XYZ.prototype.changed);
86507
86508goog.exportProperty(
86509 ol.source.XYZ.prototype,
86510 'dispatchEvent',
86511 ol.source.XYZ.prototype.dispatchEvent);
86512
86513goog.exportProperty(
86514 ol.source.XYZ.prototype,
86515 'getRevision',
86516 ol.source.XYZ.prototype.getRevision);
86517
86518goog.exportProperty(
86519 ol.source.XYZ.prototype,
86520 'on',
86521 ol.source.XYZ.prototype.on);
86522
86523goog.exportProperty(
86524 ol.source.XYZ.prototype,
86525 'once',
86526 ol.source.XYZ.prototype.once);
86527
86528goog.exportProperty(
86529 ol.source.XYZ.prototype,
86530 'un',
86531 ol.source.XYZ.prototype.un);
86532
86533goog.exportProperty(
86534 ol.source.CartoDB.prototype,
86535 'setRenderReprojectionEdges',
86536 ol.source.CartoDB.prototype.setRenderReprojectionEdges);
86537
86538goog.exportProperty(
86539 ol.source.CartoDB.prototype,
86540 'setTileGridForProjection',
86541 ol.source.CartoDB.prototype.setTileGridForProjection);
86542
86543goog.exportProperty(
86544 ol.source.CartoDB.prototype,
86545 'getTileLoadFunction',
86546 ol.source.CartoDB.prototype.getTileLoadFunction);
86547
86548goog.exportProperty(
86549 ol.source.CartoDB.prototype,
86550 'getTileUrlFunction',
86551 ol.source.CartoDB.prototype.getTileUrlFunction);
86552
86553goog.exportProperty(
86554 ol.source.CartoDB.prototype,
86555 'getUrls',
86556 ol.source.CartoDB.prototype.getUrls);
86557
86558goog.exportProperty(
86559 ol.source.CartoDB.prototype,
86560 'setTileLoadFunction',
86561 ol.source.CartoDB.prototype.setTileLoadFunction);
86562
86563goog.exportProperty(
86564 ol.source.CartoDB.prototype,
86565 'setTileUrlFunction',
86566 ol.source.CartoDB.prototype.setTileUrlFunction);
86567
86568goog.exportProperty(
86569 ol.source.CartoDB.prototype,
86570 'setUrl',
86571 ol.source.CartoDB.prototype.setUrl);
86572
86573goog.exportProperty(
86574 ol.source.CartoDB.prototype,
86575 'setUrls',
86576 ol.source.CartoDB.prototype.setUrls);
86577
86578goog.exportProperty(
86579 ol.source.CartoDB.prototype,
86580 'getTileGrid',
86581 ol.source.CartoDB.prototype.getTileGrid);
86582
86583goog.exportProperty(
86584 ol.source.CartoDB.prototype,
86585 'refresh',
86586 ol.source.CartoDB.prototype.refresh);
86587
86588goog.exportProperty(
86589 ol.source.CartoDB.prototype,
86590 'getAttributions',
86591 ol.source.CartoDB.prototype.getAttributions);
86592
86593goog.exportProperty(
86594 ol.source.CartoDB.prototype,
86595 'getLogo',
86596 ol.source.CartoDB.prototype.getLogo);
86597
86598goog.exportProperty(
86599 ol.source.CartoDB.prototype,
86600 'getProjection',
86601 ol.source.CartoDB.prototype.getProjection);
86602
86603goog.exportProperty(
86604 ol.source.CartoDB.prototype,
86605 'getState',
86606 ol.source.CartoDB.prototype.getState);
86607
86608goog.exportProperty(
86609 ol.source.CartoDB.prototype,
86610 'setAttributions',
86611 ol.source.CartoDB.prototype.setAttributions);
86612
86613goog.exportProperty(
86614 ol.source.CartoDB.prototype,
86615 'get',
86616 ol.source.CartoDB.prototype.get);
86617
86618goog.exportProperty(
86619 ol.source.CartoDB.prototype,
86620 'getKeys',
86621 ol.source.CartoDB.prototype.getKeys);
86622
86623goog.exportProperty(
86624 ol.source.CartoDB.prototype,
86625 'getProperties',
86626 ol.source.CartoDB.prototype.getProperties);
86627
86628goog.exportProperty(
86629 ol.source.CartoDB.prototype,
86630 'set',
86631 ol.source.CartoDB.prototype.set);
86632
86633goog.exportProperty(
86634 ol.source.CartoDB.prototype,
86635 'setProperties',
86636 ol.source.CartoDB.prototype.setProperties);
86637
86638goog.exportProperty(
86639 ol.source.CartoDB.prototype,
86640 'unset',
86641 ol.source.CartoDB.prototype.unset);
86642
86643goog.exportProperty(
86644 ol.source.CartoDB.prototype,
86645 'changed',
86646 ol.source.CartoDB.prototype.changed);
86647
86648goog.exportProperty(
86649 ol.source.CartoDB.prototype,
86650 'dispatchEvent',
86651 ol.source.CartoDB.prototype.dispatchEvent);
86652
86653goog.exportProperty(
86654 ol.source.CartoDB.prototype,
86655 'getRevision',
86656 ol.source.CartoDB.prototype.getRevision);
86657
86658goog.exportProperty(
86659 ol.source.CartoDB.prototype,
86660 'on',
86661 ol.source.CartoDB.prototype.on);
86662
86663goog.exportProperty(
86664 ol.source.CartoDB.prototype,
86665 'once',
86666 ol.source.CartoDB.prototype.once);
86667
86668goog.exportProperty(
86669 ol.source.CartoDB.prototype,
86670 'un',
86671 ol.source.CartoDB.prototype.un);
86672
86673goog.exportProperty(
86674 ol.source.Vector.prototype,
86675 'getAttributions',
86676 ol.source.Vector.prototype.getAttributions);
86677
86678goog.exportProperty(
86679 ol.source.Vector.prototype,
86680 'getLogo',
86681 ol.source.Vector.prototype.getLogo);
86682
86683goog.exportProperty(
86684 ol.source.Vector.prototype,
86685 'getProjection',
86686 ol.source.Vector.prototype.getProjection);
86687
86688goog.exportProperty(
86689 ol.source.Vector.prototype,
86690 'getState',
86691 ol.source.Vector.prototype.getState);
86692
86693goog.exportProperty(
86694 ol.source.Vector.prototype,
86695 'refresh',
86696 ol.source.Vector.prototype.refresh);
86697
86698goog.exportProperty(
86699 ol.source.Vector.prototype,
86700 'setAttributions',
86701 ol.source.Vector.prototype.setAttributions);
86702
86703goog.exportProperty(
86704 ol.source.Vector.prototype,
86705 'get',
86706 ol.source.Vector.prototype.get);
86707
86708goog.exportProperty(
86709 ol.source.Vector.prototype,
86710 'getKeys',
86711 ol.source.Vector.prototype.getKeys);
86712
86713goog.exportProperty(
86714 ol.source.Vector.prototype,
86715 'getProperties',
86716 ol.source.Vector.prototype.getProperties);
86717
86718goog.exportProperty(
86719 ol.source.Vector.prototype,
86720 'set',
86721 ol.source.Vector.prototype.set);
86722
86723goog.exportProperty(
86724 ol.source.Vector.prototype,
86725 'setProperties',
86726 ol.source.Vector.prototype.setProperties);
86727
86728goog.exportProperty(
86729 ol.source.Vector.prototype,
86730 'unset',
86731 ol.source.Vector.prototype.unset);
86732
86733goog.exportProperty(
86734 ol.source.Vector.prototype,
86735 'changed',
86736 ol.source.Vector.prototype.changed);
86737
86738goog.exportProperty(
86739 ol.source.Vector.prototype,
86740 'dispatchEvent',
86741 ol.source.Vector.prototype.dispatchEvent);
86742
86743goog.exportProperty(
86744 ol.source.Vector.prototype,
86745 'getRevision',
86746 ol.source.Vector.prototype.getRevision);
86747
86748goog.exportProperty(
86749 ol.source.Vector.prototype,
86750 'on',
86751 ol.source.Vector.prototype.on);
86752
86753goog.exportProperty(
86754 ol.source.Vector.prototype,
86755 'once',
86756 ol.source.Vector.prototype.once);
86757
86758goog.exportProperty(
86759 ol.source.Vector.prototype,
86760 'un',
86761 ol.source.Vector.prototype.un);
86762
86763goog.exportProperty(
86764 ol.source.Cluster.prototype,
86765 'addFeature',
86766 ol.source.Cluster.prototype.addFeature);
86767
86768goog.exportProperty(
86769 ol.source.Cluster.prototype,
86770 'addFeatures',
86771 ol.source.Cluster.prototype.addFeatures);
86772
86773goog.exportProperty(
86774 ol.source.Cluster.prototype,
86775 'clear',
86776 ol.source.Cluster.prototype.clear);
86777
86778goog.exportProperty(
86779 ol.source.Cluster.prototype,
86780 'forEachFeature',
86781 ol.source.Cluster.prototype.forEachFeature);
86782
86783goog.exportProperty(
86784 ol.source.Cluster.prototype,
86785 'forEachFeatureInExtent',
86786 ol.source.Cluster.prototype.forEachFeatureInExtent);
86787
86788goog.exportProperty(
86789 ol.source.Cluster.prototype,
86790 'forEachFeatureIntersectingExtent',
86791 ol.source.Cluster.prototype.forEachFeatureIntersectingExtent);
86792
86793goog.exportProperty(
86794 ol.source.Cluster.prototype,
86795 'getFeaturesCollection',
86796 ol.source.Cluster.prototype.getFeaturesCollection);
86797
86798goog.exportProperty(
86799 ol.source.Cluster.prototype,
86800 'getFeatures',
86801 ol.source.Cluster.prototype.getFeatures);
86802
86803goog.exportProperty(
86804 ol.source.Cluster.prototype,
86805 'getFeaturesAtCoordinate',
86806 ol.source.Cluster.prototype.getFeaturesAtCoordinate);
86807
86808goog.exportProperty(
86809 ol.source.Cluster.prototype,
86810 'getFeaturesInExtent',
86811 ol.source.Cluster.prototype.getFeaturesInExtent);
86812
86813goog.exportProperty(
86814 ol.source.Cluster.prototype,
86815 'getClosestFeatureToCoordinate',
86816 ol.source.Cluster.prototype.getClosestFeatureToCoordinate);
86817
86818goog.exportProperty(
86819 ol.source.Cluster.prototype,
86820 'getExtent',
86821 ol.source.Cluster.prototype.getExtent);
86822
86823goog.exportProperty(
86824 ol.source.Cluster.prototype,
86825 'getFeatureById',
86826 ol.source.Cluster.prototype.getFeatureById);
86827
86828goog.exportProperty(
86829 ol.source.Cluster.prototype,
86830 'getFormat',
86831 ol.source.Cluster.prototype.getFormat);
86832
86833goog.exportProperty(
86834 ol.source.Cluster.prototype,
86835 'getUrl',
86836 ol.source.Cluster.prototype.getUrl);
86837
86838goog.exportProperty(
86839 ol.source.Cluster.prototype,
86840 'removeFeature',
86841 ol.source.Cluster.prototype.removeFeature);
86842
86843goog.exportProperty(
86844 ol.source.Cluster.prototype,
86845 'getAttributions',
86846 ol.source.Cluster.prototype.getAttributions);
86847
86848goog.exportProperty(
86849 ol.source.Cluster.prototype,
86850 'getLogo',
86851 ol.source.Cluster.prototype.getLogo);
86852
86853goog.exportProperty(
86854 ol.source.Cluster.prototype,
86855 'getProjection',
86856 ol.source.Cluster.prototype.getProjection);
86857
86858goog.exportProperty(
86859 ol.source.Cluster.prototype,
86860 'getState',
86861 ol.source.Cluster.prototype.getState);
86862
86863goog.exportProperty(
86864 ol.source.Cluster.prototype,
86865 'refresh',
86866 ol.source.Cluster.prototype.refresh);
86867
86868goog.exportProperty(
86869 ol.source.Cluster.prototype,
86870 'setAttributions',
86871 ol.source.Cluster.prototype.setAttributions);
86872
86873goog.exportProperty(
86874 ol.source.Cluster.prototype,
86875 'get',
86876 ol.source.Cluster.prototype.get);
86877
86878goog.exportProperty(
86879 ol.source.Cluster.prototype,
86880 'getKeys',
86881 ol.source.Cluster.prototype.getKeys);
86882
86883goog.exportProperty(
86884 ol.source.Cluster.prototype,
86885 'getProperties',
86886 ol.source.Cluster.prototype.getProperties);
86887
86888goog.exportProperty(
86889 ol.source.Cluster.prototype,
86890 'set',
86891 ol.source.Cluster.prototype.set);
86892
86893goog.exportProperty(
86894 ol.source.Cluster.prototype,
86895 'setProperties',
86896 ol.source.Cluster.prototype.setProperties);
86897
86898goog.exportProperty(
86899 ol.source.Cluster.prototype,
86900 'unset',
86901 ol.source.Cluster.prototype.unset);
86902
86903goog.exportProperty(
86904 ol.source.Cluster.prototype,
86905 'changed',
86906 ol.source.Cluster.prototype.changed);
86907
86908goog.exportProperty(
86909 ol.source.Cluster.prototype,
86910 'dispatchEvent',
86911 ol.source.Cluster.prototype.dispatchEvent);
86912
86913goog.exportProperty(
86914 ol.source.Cluster.prototype,
86915 'getRevision',
86916 ol.source.Cluster.prototype.getRevision);
86917
86918goog.exportProperty(
86919 ol.source.Cluster.prototype,
86920 'on',
86921 ol.source.Cluster.prototype.on);
86922
86923goog.exportProperty(
86924 ol.source.Cluster.prototype,
86925 'once',
86926 ol.source.Cluster.prototype.once);
86927
86928goog.exportProperty(
86929 ol.source.Cluster.prototype,
86930 'un',
86931 ol.source.Cluster.prototype.un);
86932
86933goog.exportProperty(
86934 ol.source.Image.prototype,
86935 'getAttributions',
86936 ol.source.Image.prototype.getAttributions);
86937
86938goog.exportProperty(
86939 ol.source.Image.prototype,
86940 'getLogo',
86941 ol.source.Image.prototype.getLogo);
86942
86943goog.exportProperty(
86944 ol.source.Image.prototype,
86945 'getProjection',
86946 ol.source.Image.prototype.getProjection);
86947
86948goog.exportProperty(
86949 ol.source.Image.prototype,
86950 'getState',
86951 ol.source.Image.prototype.getState);
86952
86953goog.exportProperty(
86954 ol.source.Image.prototype,
86955 'refresh',
86956 ol.source.Image.prototype.refresh);
86957
86958goog.exportProperty(
86959 ol.source.Image.prototype,
86960 'setAttributions',
86961 ol.source.Image.prototype.setAttributions);
86962
86963goog.exportProperty(
86964 ol.source.Image.prototype,
86965 'get',
86966 ol.source.Image.prototype.get);
86967
86968goog.exportProperty(
86969 ol.source.Image.prototype,
86970 'getKeys',
86971 ol.source.Image.prototype.getKeys);
86972
86973goog.exportProperty(
86974 ol.source.Image.prototype,
86975 'getProperties',
86976 ol.source.Image.prototype.getProperties);
86977
86978goog.exportProperty(
86979 ol.source.Image.prototype,
86980 'set',
86981 ol.source.Image.prototype.set);
86982
86983goog.exportProperty(
86984 ol.source.Image.prototype,
86985 'setProperties',
86986 ol.source.Image.prototype.setProperties);
86987
86988goog.exportProperty(
86989 ol.source.Image.prototype,
86990 'unset',
86991 ol.source.Image.prototype.unset);
86992
86993goog.exportProperty(
86994 ol.source.Image.prototype,
86995 'changed',
86996 ol.source.Image.prototype.changed);
86997
86998goog.exportProperty(
86999 ol.source.Image.prototype,
87000 'dispatchEvent',
87001 ol.source.Image.prototype.dispatchEvent);
87002
87003goog.exportProperty(
87004 ol.source.Image.prototype,
87005 'getRevision',
87006 ol.source.Image.prototype.getRevision);
87007
87008goog.exportProperty(
87009 ol.source.Image.prototype,
87010 'on',
87011 ol.source.Image.prototype.on);
87012
87013goog.exportProperty(
87014 ol.source.Image.prototype,
87015 'once',
87016 ol.source.Image.prototype.once);
87017
87018goog.exportProperty(
87019 ol.source.Image.prototype,
87020 'un',
87021 ol.source.Image.prototype.un);
87022
87023goog.exportProperty(
87024 ol.source.Image.Event.prototype,
87025 'type',
87026 ol.source.Image.Event.prototype.type);
87027
87028goog.exportProperty(
87029 ol.source.Image.Event.prototype,
87030 'target',
87031 ol.source.Image.Event.prototype.target);
87032
87033goog.exportProperty(
87034 ol.source.Image.Event.prototype,
87035 'preventDefault',
87036 ol.source.Image.Event.prototype.preventDefault);
87037
87038goog.exportProperty(
87039 ol.source.Image.Event.prototype,
87040 'stopPropagation',
87041 ol.source.Image.Event.prototype.stopPropagation);
87042
87043goog.exportProperty(
87044 ol.source.ImageArcGISRest.prototype,
87045 'getAttributions',
87046 ol.source.ImageArcGISRest.prototype.getAttributions);
87047
87048goog.exportProperty(
87049 ol.source.ImageArcGISRest.prototype,
87050 'getLogo',
87051 ol.source.ImageArcGISRest.prototype.getLogo);
87052
87053goog.exportProperty(
87054 ol.source.ImageArcGISRest.prototype,
87055 'getProjection',
87056 ol.source.ImageArcGISRest.prototype.getProjection);
87057
87058goog.exportProperty(
87059 ol.source.ImageArcGISRest.prototype,
87060 'getState',
87061 ol.source.ImageArcGISRest.prototype.getState);
87062
87063goog.exportProperty(
87064 ol.source.ImageArcGISRest.prototype,
87065 'refresh',
87066 ol.source.ImageArcGISRest.prototype.refresh);
87067
87068goog.exportProperty(
87069 ol.source.ImageArcGISRest.prototype,
87070 'setAttributions',
87071 ol.source.ImageArcGISRest.prototype.setAttributions);
87072
87073goog.exportProperty(
87074 ol.source.ImageArcGISRest.prototype,
87075 'get',
87076 ol.source.ImageArcGISRest.prototype.get);
87077
87078goog.exportProperty(
87079 ol.source.ImageArcGISRest.prototype,
87080 'getKeys',
87081 ol.source.ImageArcGISRest.prototype.getKeys);
87082
87083goog.exportProperty(
87084 ol.source.ImageArcGISRest.prototype,
87085 'getProperties',
87086 ol.source.ImageArcGISRest.prototype.getProperties);
87087
87088goog.exportProperty(
87089 ol.source.ImageArcGISRest.prototype,
87090 'set',
87091 ol.source.ImageArcGISRest.prototype.set);
87092
87093goog.exportProperty(
87094 ol.source.ImageArcGISRest.prototype,
87095 'setProperties',
87096 ol.source.ImageArcGISRest.prototype.setProperties);
87097
87098goog.exportProperty(
87099 ol.source.ImageArcGISRest.prototype,
87100 'unset',
87101 ol.source.ImageArcGISRest.prototype.unset);
87102
87103goog.exportProperty(
87104 ol.source.ImageArcGISRest.prototype,
87105 'changed',
87106 ol.source.ImageArcGISRest.prototype.changed);
87107
87108goog.exportProperty(
87109 ol.source.ImageArcGISRest.prototype,
87110 'dispatchEvent',
87111 ol.source.ImageArcGISRest.prototype.dispatchEvent);
87112
87113goog.exportProperty(
87114 ol.source.ImageArcGISRest.prototype,
87115 'getRevision',
87116 ol.source.ImageArcGISRest.prototype.getRevision);
87117
87118goog.exportProperty(
87119 ol.source.ImageArcGISRest.prototype,
87120 'on',
87121 ol.source.ImageArcGISRest.prototype.on);
87122
87123goog.exportProperty(
87124 ol.source.ImageArcGISRest.prototype,
87125 'once',
87126 ol.source.ImageArcGISRest.prototype.once);
87127
87128goog.exportProperty(
87129 ol.source.ImageArcGISRest.prototype,
87130 'un',
87131 ol.source.ImageArcGISRest.prototype.un);
87132
87133goog.exportProperty(
87134 ol.source.ImageCanvas.prototype,
87135 'getAttributions',
87136 ol.source.ImageCanvas.prototype.getAttributions);
87137
87138goog.exportProperty(
87139 ol.source.ImageCanvas.prototype,
87140 'getLogo',
87141 ol.source.ImageCanvas.prototype.getLogo);
87142
87143goog.exportProperty(
87144 ol.source.ImageCanvas.prototype,
87145 'getProjection',
87146 ol.source.ImageCanvas.prototype.getProjection);
87147
87148goog.exportProperty(
87149 ol.source.ImageCanvas.prototype,
87150 'getState',
87151 ol.source.ImageCanvas.prototype.getState);
87152
87153goog.exportProperty(
87154 ol.source.ImageCanvas.prototype,
87155 'refresh',
87156 ol.source.ImageCanvas.prototype.refresh);
87157
87158goog.exportProperty(
87159 ol.source.ImageCanvas.prototype,
87160 'setAttributions',
87161 ol.source.ImageCanvas.prototype.setAttributions);
87162
87163goog.exportProperty(
87164 ol.source.ImageCanvas.prototype,
87165 'get',
87166 ol.source.ImageCanvas.prototype.get);
87167
87168goog.exportProperty(
87169 ol.source.ImageCanvas.prototype,
87170 'getKeys',
87171 ol.source.ImageCanvas.prototype.getKeys);
87172
87173goog.exportProperty(
87174 ol.source.ImageCanvas.prototype,
87175 'getProperties',
87176 ol.source.ImageCanvas.prototype.getProperties);
87177
87178goog.exportProperty(
87179 ol.source.ImageCanvas.prototype,
87180 'set',
87181 ol.source.ImageCanvas.prototype.set);
87182
87183goog.exportProperty(
87184 ol.source.ImageCanvas.prototype,
87185 'setProperties',
87186 ol.source.ImageCanvas.prototype.setProperties);
87187
87188goog.exportProperty(
87189 ol.source.ImageCanvas.prototype,
87190 'unset',
87191 ol.source.ImageCanvas.prototype.unset);
87192
87193goog.exportProperty(
87194 ol.source.ImageCanvas.prototype,
87195 'changed',
87196 ol.source.ImageCanvas.prototype.changed);
87197
87198goog.exportProperty(
87199 ol.source.ImageCanvas.prototype,
87200 'dispatchEvent',
87201 ol.source.ImageCanvas.prototype.dispatchEvent);
87202
87203goog.exportProperty(
87204 ol.source.ImageCanvas.prototype,
87205 'getRevision',
87206 ol.source.ImageCanvas.prototype.getRevision);
87207
87208goog.exportProperty(
87209 ol.source.ImageCanvas.prototype,
87210 'on',
87211 ol.source.ImageCanvas.prototype.on);
87212
87213goog.exportProperty(
87214 ol.source.ImageCanvas.prototype,
87215 'once',
87216 ol.source.ImageCanvas.prototype.once);
87217
87218goog.exportProperty(
87219 ol.source.ImageCanvas.prototype,
87220 'un',
87221 ol.source.ImageCanvas.prototype.un);
87222
87223goog.exportProperty(
87224 ol.source.ImageMapGuide.prototype,
87225 'getAttributions',
87226 ol.source.ImageMapGuide.prototype.getAttributions);
87227
87228goog.exportProperty(
87229 ol.source.ImageMapGuide.prototype,
87230 'getLogo',
87231 ol.source.ImageMapGuide.prototype.getLogo);
87232
87233goog.exportProperty(
87234 ol.source.ImageMapGuide.prototype,
87235 'getProjection',
87236 ol.source.ImageMapGuide.prototype.getProjection);
87237
87238goog.exportProperty(
87239 ol.source.ImageMapGuide.prototype,
87240 'getState',
87241 ol.source.ImageMapGuide.prototype.getState);
87242
87243goog.exportProperty(
87244 ol.source.ImageMapGuide.prototype,
87245 'refresh',
87246 ol.source.ImageMapGuide.prototype.refresh);
87247
87248goog.exportProperty(
87249 ol.source.ImageMapGuide.prototype,
87250 'setAttributions',
87251 ol.source.ImageMapGuide.prototype.setAttributions);
87252
87253goog.exportProperty(
87254 ol.source.ImageMapGuide.prototype,
87255 'get',
87256 ol.source.ImageMapGuide.prototype.get);
87257
87258goog.exportProperty(
87259 ol.source.ImageMapGuide.prototype,
87260 'getKeys',
87261 ol.source.ImageMapGuide.prototype.getKeys);
87262
87263goog.exportProperty(
87264 ol.source.ImageMapGuide.prototype,
87265 'getProperties',
87266 ol.source.ImageMapGuide.prototype.getProperties);
87267
87268goog.exportProperty(
87269 ol.source.ImageMapGuide.prototype,
87270 'set',
87271 ol.source.ImageMapGuide.prototype.set);
87272
87273goog.exportProperty(
87274 ol.source.ImageMapGuide.prototype,
87275 'setProperties',
87276 ol.source.ImageMapGuide.prototype.setProperties);
87277
87278goog.exportProperty(
87279 ol.source.ImageMapGuide.prototype,
87280 'unset',
87281 ol.source.ImageMapGuide.prototype.unset);
87282
87283goog.exportProperty(
87284 ol.source.ImageMapGuide.prototype,
87285 'changed',
87286 ol.source.ImageMapGuide.prototype.changed);
87287
87288goog.exportProperty(
87289 ol.source.ImageMapGuide.prototype,
87290 'dispatchEvent',
87291 ol.source.ImageMapGuide.prototype.dispatchEvent);
87292
87293goog.exportProperty(
87294 ol.source.ImageMapGuide.prototype,
87295 'getRevision',
87296 ol.source.ImageMapGuide.prototype.getRevision);
87297
87298goog.exportProperty(
87299 ol.source.ImageMapGuide.prototype,
87300 'on',
87301 ol.source.ImageMapGuide.prototype.on);
87302
87303goog.exportProperty(
87304 ol.source.ImageMapGuide.prototype,
87305 'once',
87306 ol.source.ImageMapGuide.prototype.once);
87307
87308goog.exportProperty(
87309 ol.source.ImageMapGuide.prototype,
87310 'un',
87311 ol.source.ImageMapGuide.prototype.un);
87312
87313goog.exportProperty(
87314 ol.source.ImageStatic.prototype,
87315 'getAttributions',
87316 ol.source.ImageStatic.prototype.getAttributions);
87317
87318goog.exportProperty(
87319 ol.source.ImageStatic.prototype,
87320 'getLogo',
87321 ol.source.ImageStatic.prototype.getLogo);
87322
87323goog.exportProperty(
87324 ol.source.ImageStatic.prototype,
87325 'getProjection',
87326 ol.source.ImageStatic.prototype.getProjection);
87327
87328goog.exportProperty(
87329 ol.source.ImageStatic.prototype,
87330 'getState',
87331 ol.source.ImageStatic.prototype.getState);
87332
87333goog.exportProperty(
87334 ol.source.ImageStatic.prototype,
87335 'refresh',
87336 ol.source.ImageStatic.prototype.refresh);
87337
87338goog.exportProperty(
87339 ol.source.ImageStatic.prototype,
87340 'setAttributions',
87341 ol.source.ImageStatic.prototype.setAttributions);
87342
87343goog.exportProperty(
87344 ol.source.ImageStatic.prototype,
87345 'get',
87346 ol.source.ImageStatic.prototype.get);
87347
87348goog.exportProperty(
87349 ol.source.ImageStatic.prototype,
87350 'getKeys',
87351 ol.source.ImageStatic.prototype.getKeys);
87352
87353goog.exportProperty(
87354 ol.source.ImageStatic.prototype,
87355 'getProperties',
87356 ol.source.ImageStatic.prototype.getProperties);
87357
87358goog.exportProperty(
87359 ol.source.ImageStatic.prototype,
87360 'set',
87361 ol.source.ImageStatic.prototype.set);
87362
87363goog.exportProperty(
87364 ol.source.ImageStatic.prototype,
87365 'setProperties',
87366 ol.source.ImageStatic.prototype.setProperties);
87367
87368goog.exportProperty(
87369 ol.source.ImageStatic.prototype,
87370 'unset',
87371 ol.source.ImageStatic.prototype.unset);
87372
87373goog.exportProperty(
87374 ol.source.ImageStatic.prototype,
87375 'changed',
87376 ol.source.ImageStatic.prototype.changed);
87377
87378goog.exportProperty(
87379 ol.source.ImageStatic.prototype,
87380 'dispatchEvent',
87381 ol.source.ImageStatic.prototype.dispatchEvent);
87382
87383goog.exportProperty(
87384 ol.source.ImageStatic.prototype,
87385 'getRevision',
87386 ol.source.ImageStatic.prototype.getRevision);
87387
87388goog.exportProperty(
87389 ol.source.ImageStatic.prototype,
87390 'on',
87391 ol.source.ImageStatic.prototype.on);
87392
87393goog.exportProperty(
87394 ol.source.ImageStatic.prototype,
87395 'once',
87396 ol.source.ImageStatic.prototype.once);
87397
87398goog.exportProperty(
87399 ol.source.ImageStatic.prototype,
87400 'un',
87401 ol.source.ImageStatic.prototype.un);
87402
87403goog.exportProperty(
87404 ol.source.ImageVector.prototype,
87405 'getAttributions',
87406 ol.source.ImageVector.prototype.getAttributions);
87407
87408goog.exportProperty(
87409 ol.source.ImageVector.prototype,
87410 'getLogo',
87411 ol.source.ImageVector.prototype.getLogo);
87412
87413goog.exportProperty(
87414 ol.source.ImageVector.prototype,
87415 'getProjection',
87416 ol.source.ImageVector.prototype.getProjection);
87417
87418goog.exportProperty(
87419 ol.source.ImageVector.prototype,
87420 'getState',
87421 ol.source.ImageVector.prototype.getState);
87422
87423goog.exportProperty(
87424 ol.source.ImageVector.prototype,
87425 'refresh',
87426 ol.source.ImageVector.prototype.refresh);
87427
87428goog.exportProperty(
87429 ol.source.ImageVector.prototype,
87430 'setAttributions',
87431 ol.source.ImageVector.prototype.setAttributions);
87432
87433goog.exportProperty(
87434 ol.source.ImageVector.prototype,
87435 'get',
87436 ol.source.ImageVector.prototype.get);
87437
87438goog.exportProperty(
87439 ol.source.ImageVector.prototype,
87440 'getKeys',
87441 ol.source.ImageVector.prototype.getKeys);
87442
87443goog.exportProperty(
87444 ol.source.ImageVector.prototype,
87445 'getProperties',
87446 ol.source.ImageVector.prototype.getProperties);
87447
87448goog.exportProperty(
87449 ol.source.ImageVector.prototype,
87450 'set',
87451 ol.source.ImageVector.prototype.set);
87452
87453goog.exportProperty(
87454 ol.source.ImageVector.prototype,
87455 'setProperties',
87456 ol.source.ImageVector.prototype.setProperties);
87457
87458goog.exportProperty(
87459 ol.source.ImageVector.prototype,
87460 'unset',
87461 ol.source.ImageVector.prototype.unset);
87462
87463goog.exportProperty(
87464 ol.source.ImageVector.prototype,
87465 'changed',
87466 ol.source.ImageVector.prototype.changed);
87467
87468goog.exportProperty(
87469 ol.source.ImageVector.prototype,
87470 'dispatchEvent',
87471 ol.source.ImageVector.prototype.dispatchEvent);
87472
87473goog.exportProperty(
87474 ol.source.ImageVector.prototype,
87475 'getRevision',
87476 ol.source.ImageVector.prototype.getRevision);
87477
87478goog.exportProperty(
87479 ol.source.ImageVector.prototype,
87480 'on',
87481 ol.source.ImageVector.prototype.on);
87482
87483goog.exportProperty(
87484 ol.source.ImageVector.prototype,
87485 'once',
87486 ol.source.ImageVector.prototype.once);
87487
87488goog.exportProperty(
87489 ol.source.ImageVector.prototype,
87490 'un',
87491 ol.source.ImageVector.prototype.un);
87492
87493goog.exportProperty(
87494 ol.source.ImageWMS.prototype,
87495 'getAttributions',
87496 ol.source.ImageWMS.prototype.getAttributions);
87497
87498goog.exportProperty(
87499 ol.source.ImageWMS.prototype,
87500 'getLogo',
87501 ol.source.ImageWMS.prototype.getLogo);
87502
87503goog.exportProperty(
87504 ol.source.ImageWMS.prototype,
87505 'getProjection',
87506 ol.source.ImageWMS.prototype.getProjection);
87507
87508goog.exportProperty(
87509 ol.source.ImageWMS.prototype,
87510 'getState',
87511 ol.source.ImageWMS.prototype.getState);
87512
87513goog.exportProperty(
87514 ol.source.ImageWMS.prototype,
87515 'refresh',
87516 ol.source.ImageWMS.prototype.refresh);
87517
87518goog.exportProperty(
87519 ol.source.ImageWMS.prototype,
87520 'setAttributions',
87521 ol.source.ImageWMS.prototype.setAttributions);
87522
87523goog.exportProperty(
87524 ol.source.ImageWMS.prototype,
87525 'get',
87526 ol.source.ImageWMS.prototype.get);
87527
87528goog.exportProperty(
87529 ol.source.ImageWMS.prototype,
87530 'getKeys',
87531 ol.source.ImageWMS.prototype.getKeys);
87532
87533goog.exportProperty(
87534 ol.source.ImageWMS.prototype,
87535 'getProperties',
87536 ol.source.ImageWMS.prototype.getProperties);
87537
87538goog.exportProperty(
87539 ol.source.ImageWMS.prototype,
87540 'set',
87541 ol.source.ImageWMS.prototype.set);
87542
87543goog.exportProperty(
87544 ol.source.ImageWMS.prototype,
87545 'setProperties',
87546 ol.source.ImageWMS.prototype.setProperties);
87547
87548goog.exportProperty(
87549 ol.source.ImageWMS.prototype,
87550 'unset',
87551 ol.source.ImageWMS.prototype.unset);
87552
87553goog.exportProperty(
87554 ol.source.ImageWMS.prototype,
87555 'changed',
87556 ol.source.ImageWMS.prototype.changed);
87557
87558goog.exportProperty(
87559 ol.source.ImageWMS.prototype,
87560 'dispatchEvent',
87561 ol.source.ImageWMS.prototype.dispatchEvent);
87562
87563goog.exportProperty(
87564 ol.source.ImageWMS.prototype,
87565 'getRevision',
87566 ol.source.ImageWMS.prototype.getRevision);
87567
87568goog.exportProperty(
87569 ol.source.ImageWMS.prototype,
87570 'on',
87571 ol.source.ImageWMS.prototype.on);
87572
87573goog.exportProperty(
87574 ol.source.ImageWMS.prototype,
87575 'once',
87576 ol.source.ImageWMS.prototype.once);
87577
87578goog.exportProperty(
87579 ol.source.ImageWMS.prototype,
87580 'un',
87581 ol.source.ImageWMS.prototype.un);
87582
87583goog.exportProperty(
87584 ol.source.OSM.prototype,
87585 'setRenderReprojectionEdges',
87586 ol.source.OSM.prototype.setRenderReprojectionEdges);
87587
87588goog.exportProperty(
87589 ol.source.OSM.prototype,
87590 'setTileGridForProjection',
87591 ol.source.OSM.prototype.setTileGridForProjection);
87592
87593goog.exportProperty(
87594 ol.source.OSM.prototype,
87595 'getTileLoadFunction',
87596 ol.source.OSM.prototype.getTileLoadFunction);
87597
87598goog.exportProperty(
87599 ol.source.OSM.prototype,
87600 'getTileUrlFunction',
87601 ol.source.OSM.prototype.getTileUrlFunction);
87602
87603goog.exportProperty(
87604 ol.source.OSM.prototype,
87605 'getUrls',
87606 ol.source.OSM.prototype.getUrls);
87607
87608goog.exportProperty(
87609 ol.source.OSM.prototype,
87610 'setTileLoadFunction',
87611 ol.source.OSM.prototype.setTileLoadFunction);
87612
87613goog.exportProperty(
87614 ol.source.OSM.prototype,
87615 'setTileUrlFunction',
87616 ol.source.OSM.prototype.setTileUrlFunction);
87617
87618goog.exportProperty(
87619 ol.source.OSM.prototype,
87620 'setUrl',
87621 ol.source.OSM.prototype.setUrl);
87622
87623goog.exportProperty(
87624 ol.source.OSM.prototype,
87625 'setUrls',
87626 ol.source.OSM.prototype.setUrls);
87627
87628goog.exportProperty(
87629 ol.source.OSM.prototype,
87630 'getTileGrid',
87631 ol.source.OSM.prototype.getTileGrid);
87632
87633goog.exportProperty(
87634 ol.source.OSM.prototype,
87635 'refresh',
87636 ol.source.OSM.prototype.refresh);
87637
87638goog.exportProperty(
87639 ol.source.OSM.prototype,
87640 'getAttributions',
87641 ol.source.OSM.prototype.getAttributions);
87642
87643goog.exportProperty(
87644 ol.source.OSM.prototype,
87645 'getLogo',
87646 ol.source.OSM.prototype.getLogo);
87647
87648goog.exportProperty(
87649 ol.source.OSM.prototype,
87650 'getProjection',
87651 ol.source.OSM.prototype.getProjection);
87652
87653goog.exportProperty(
87654 ol.source.OSM.prototype,
87655 'getState',
87656 ol.source.OSM.prototype.getState);
87657
87658goog.exportProperty(
87659 ol.source.OSM.prototype,
87660 'setAttributions',
87661 ol.source.OSM.prototype.setAttributions);
87662
87663goog.exportProperty(
87664 ol.source.OSM.prototype,
87665 'get',
87666 ol.source.OSM.prototype.get);
87667
87668goog.exportProperty(
87669 ol.source.OSM.prototype,
87670 'getKeys',
87671 ol.source.OSM.prototype.getKeys);
87672
87673goog.exportProperty(
87674 ol.source.OSM.prototype,
87675 'getProperties',
87676 ol.source.OSM.prototype.getProperties);
87677
87678goog.exportProperty(
87679 ol.source.OSM.prototype,
87680 'set',
87681 ol.source.OSM.prototype.set);
87682
87683goog.exportProperty(
87684 ol.source.OSM.prototype,
87685 'setProperties',
87686 ol.source.OSM.prototype.setProperties);
87687
87688goog.exportProperty(
87689 ol.source.OSM.prototype,
87690 'unset',
87691 ol.source.OSM.prototype.unset);
87692
87693goog.exportProperty(
87694 ol.source.OSM.prototype,
87695 'changed',
87696 ol.source.OSM.prototype.changed);
87697
87698goog.exportProperty(
87699 ol.source.OSM.prototype,
87700 'dispatchEvent',
87701 ol.source.OSM.prototype.dispatchEvent);
87702
87703goog.exportProperty(
87704 ol.source.OSM.prototype,
87705 'getRevision',
87706 ol.source.OSM.prototype.getRevision);
87707
87708goog.exportProperty(
87709 ol.source.OSM.prototype,
87710 'on',
87711 ol.source.OSM.prototype.on);
87712
87713goog.exportProperty(
87714 ol.source.OSM.prototype,
87715 'once',
87716 ol.source.OSM.prototype.once);
87717
87718goog.exportProperty(
87719 ol.source.OSM.prototype,
87720 'un',
87721 ol.source.OSM.prototype.un);
87722
87723goog.exportProperty(
87724 ol.source.Raster.prototype,
87725 'getAttributions',
87726 ol.source.Raster.prototype.getAttributions);
87727
87728goog.exportProperty(
87729 ol.source.Raster.prototype,
87730 'getLogo',
87731 ol.source.Raster.prototype.getLogo);
87732
87733goog.exportProperty(
87734 ol.source.Raster.prototype,
87735 'getProjection',
87736 ol.source.Raster.prototype.getProjection);
87737
87738goog.exportProperty(
87739 ol.source.Raster.prototype,
87740 'getState',
87741 ol.source.Raster.prototype.getState);
87742
87743goog.exportProperty(
87744 ol.source.Raster.prototype,
87745 'refresh',
87746 ol.source.Raster.prototype.refresh);
87747
87748goog.exportProperty(
87749 ol.source.Raster.prototype,
87750 'setAttributions',
87751 ol.source.Raster.prototype.setAttributions);
87752
87753goog.exportProperty(
87754 ol.source.Raster.prototype,
87755 'get',
87756 ol.source.Raster.prototype.get);
87757
87758goog.exportProperty(
87759 ol.source.Raster.prototype,
87760 'getKeys',
87761 ol.source.Raster.prototype.getKeys);
87762
87763goog.exportProperty(
87764 ol.source.Raster.prototype,
87765 'getProperties',
87766 ol.source.Raster.prototype.getProperties);
87767
87768goog.exportProperty(
87769 ol.source.Raster.prototype,
87770 'set',
87771 ol.source.Raster.prototype.set);
87772
87773goog.exportProperty(
87774 ol.source.Raster.prototype,
87775 'setProperties',
87776 ol.source.Raster.prototype.setProperties);
87777
87778goog.exportProperty(
87779 ol.source.Raster.prototype,
87780 'unset',
87781 ol.source.Raster.prototype.unset);
87782
87783goog.exportProperty(
87784 ol.source.Raster.prototype,
87785 'changed',
87786 ol.source.Raster.prototype.changed);
87787
87788goog.exportProperty(
87789 ol.source.Raster.prototype,
87790 'dispatchEvent',
87791 ol.source.Raster.prototype.dispatchEvent);
87792
87793goog.exportProperty(
87794 ol.source.Raster.prototype,
87795 'getRevision',
87796 ol.source.Raster.prototype.getRevision);
87797
87798goog.exportProperty(
87799 ol.source.Raster.prototype,
87800 'on',
87801 ol.source.Raster.prototype.on);
87802
87803goog.exportProperty(
87804 ol.source.Raster.prototype,
87805 'once',
87806 ol.source.Raster.prototype.once);
87807
87808goog.exportProperty(
87809 ol.source.Raster.prototype,
87810 'un',
87811 ol.source.Raster.prototype.un);
87812
87813goog.exportProperty(
87814 ol.source.Raster.Event.prototype,
87815 'type',
87816 ol.source.Raster.Event.prototype.type);
87817
87818goog.exportProperty(
87819 ol.source.Raster.Event.prototype,
87820 'target',
87821 ol.source.Raster.Event.prototype.target);
87822
87823goog.exportProperty(
87824 ol.source.Raster.Event.prototype,
87825 'preventDefault',
87826 ol.source.Raster.Event.prototype.preventDefault);
87827
87828goog.exportProperty(
87829 ol.source.Raster.Event.prototype,
87830 'stopPropagation',
87831 ol.source.Raster.Event.prototype.stopPropagation);
87832
87833goog.exportProperty(
87834 ol.source.Stamen.prototype,
87835 'setRenderReprojectionEdges',
87836 ol.source.Stamen.prototype.setRenderReprojectionEdges);
87837
87838goog.exportProperty(
87839 ol.source.Stamen.prototype,
87840 'setTileGridForProjection',
87841 ol.source.Stamen.prototype.setTileGridForProjection);
87842
87843goog.exportProperty(
87844 ol.source.Stamen.prototype,
87845 'getTileLoadFunction',
87846 ol.source.Stamen.prototype.getTileLoadFunction);
87847
87848goog.exportProperty(
87849 ol.source.Stamen.prototype,
87850 'getTileUrlFunction',
87851 ol.source.Stamen.prototype.getTileUrlFunction);
87852
87853goog.exportProperty(
87854 ol.source.Stamen.prototype,
87855 'getUrls',
87856 ol.source.Stamen.prototype.getUrls);
87857
87858goog.exportProperty(
87859 ol.source.Stamen.prototype,
87860 'setTileLoadFunction',
87861 ol.source.Stamen.prototype.setTileLoadFunction);
87862
87863goog.exportProperty(
87864 ol.source.Stamen.prototype,
87865 'setTileUrlFunction',
87866 ol.source.Stamen.prototype.setTileUrlFunction);
87867
87868goog.exportProperty(
87869 ol.source.Stamen.prototype,
87870 'setUrl',
87871 ol.source.Stamen.prototype.setUrl);
87872
87873goog.exportProperty(
87874 ol.source.Stamen.prototype,
87875 'setUrls',
87876 ol.source.Stamen.prototype.setUrls);
87877
87878goog.exportProperty(
87879 ol.source.Stamen.prototype,
87880 'getTileGrid',
87881 ol.source.Stamen.prototype.getTileGrid);
87882
87883goog.exportProperty(
87884 ol.source.Stamen.prototype,
87885 'refresh',
87886 ol.source.Stamen.prototype.refresh);
87887
87888goog.exportProperty(
87889 ol.source.Stamen.prototype,
87890 'getAttributions',
87891 ol.source.Stamen.prototype.getAttributions);
87892
87893goog.exportProperty(
87894 ol.source.Stamen.prototype,
87895 'getLogo',
87896 ol.source.Stamen.prototype.getLogo);
87897
87898goog.exportProperty(
87899 ol.source.Stamen.prototype,
87900 'getProjection',
87901 ol.source.Stamen.prototype.getProjection);
87902
87903goog.exportProperty(
87904 ol.source.Stamen.prototype,
87905 'getState',
87906 ol.source.Stamen.prototype.getState);
87907
87908goog.exportProperty(
87909 ol.source.Stamen.prototype,
87910 'setAttributions',
87911 ol.source.Stamen.prototype.setAttributions);
87912
87913goog.exportProperty(
87914 ol.source.Stamen.prototype,
87915 'get',
87916 ol.source.Stamen.prototype.get);
87917
87918goog.exportProperty(
87919 ol.source.Stamen.prototype,
87920 'getKeys',
87921 ol.source.Stamen.prototype.getKeys);
87922
87923goog.exportProperty(
87924 ol.source.Stamen.prototype,
87925 'getProperties',
87926 ol.source.Stamen.prototype.getProperties);
87927
87928goog.exportProperty(
87929 ol.source.Stamen.prototype,
87930 'set',
87931 ol.source.Stamen.prototype.set);
87932
87933goog.exportProperty(
87934 ol.source.Stamen.prototype,
87935 'setProperties',
87936 ol.source.Stamen.prototype.setProperties);
87937
87938goog.exportProperty(
87939 ol.source.Stamen.prototype,
87940 'unset',
87941 ol.source.Stamen.prototype.unset);
87942
87943goog.exportProperty(
87944 ol.source.Stamen.prototype,
87945 'changed',
87946 ol.source.Stamen.prototype.changed);
87947
87948goog.exportProperty(
87949 ol.source.Stamen.prototype,
87950 'dispatchEvent',
87951 ol.source.Stamen.prototype.dispatchEvent);
87952
87953goog.exportProperty(
87954 ol.source.Stamen.prototype,
87955 'getRevision',
87956 ol.source.Stamen.prototype.getRevision);
87957
87958goog.exportProperty(
87959 ol.source.Stamen.prototype,
87960 'on',
87961 ol.source.Stamen.prototype.on);
87962
87963goog.exportProperty(
87964 ol.source.Stamen.prototype,
87965 'once',
87966 ol.source.Stamen.prototype.once);
87967
87968goog.exportProperty(
87969 ol.source.Stamen.prototype,
87970 'un',
87971 ol.source.Stamen.prototype.un);
87972
87973goog.exportProperty(
87974 ol.source.Tile.Event.prototype,
87975 'type',
87976 ol.source.Tile.Event.prototype.type);
87977
87978goog.exportProperty(
87979 ol.source.Tile.Event.prototype,
87980 'target',
87981 ol.source.Tile.Event.prototype.target);
87982
87983goog.exportProperty(
87984 ol.source.Tile.Event.prototype,
87985 'preventDefault',
87986 ol.source.Tile.Event.prototype.preventDefault);
87987
87988goog.exportProperty(
87989 ol.source.Tile.Event.prototype,
87990 'stopPropagation',
87991 ol.source.Tile.Event.prototype.stopPropagation);
87992
87993goog.exportProperty(
87994 ol.source.TileArcGISRest.prototype,
87995 'setRenderReprojectionEdges',
87996 ol.source.TileArcGISRest.prototype.setRenderReprojectionEdges);
87997
87998goog.exportProperty(
87999 ol.source.TileArcGISRest.prototype,
88000 'setTileGridForProjection',
88001 ol.source.TileArcGISRest.prototype.setTileGridForProjection);
88002
88003goog.exportProperty(
88004 ol.source.TileArcGISRest.prototype,
88005 'getTileLoadFunction',
88006 ol.source.TileArcGISRest.prototype.getTileLoadFunction);
88007
88008goog.exportProperty(
88009 ol.source.TileArcGISRest.prototype,
88010 'getTileUrlFunction',
88011 ol.source.TileArcGISRest.prototype.getTileUrlFunction);
88012
88013goog.exportProperty(
88014 ol.source.TileArcGISRest.prototype,
88015 'getUrls',
88016 ol.source.TileArcGISRest.prototype.getUrls);
88017
88018goog.exportProperty(
88019 ol.source.TileArcGISRest.prototype,
88020 'setTileLoadFunction',
88021 ol.source.TileArcGISRest.prototype.setTileLoadFunction);
88022
88023goog.exportProperty(
88024 ol.source.TileArcGISRest.prototype,
88025 'setTileUrlFunction',
88026 ol.source.TileArcGISRest.prototype.setTileUrlFunction);
88027
88028goog.exportProperty(
88029 ol.source.TileArcGISRest.prototype,
88030 'setUrl',
88031 ol.source.TileArcGISRest.prototype.setUrl);
88032
88033goog.exportProperty(
88034 ol.source.TileArcGISRest.prototype,
88035 'setUrls',
88036 ol.source.TileArcGISRest.prototype.setUrls);
88037
88038goog.exportProperty(
88039 ol.source.TileArcGISRest.prototype,
88040 'getTileGrid',
88041 ol.source.TileArcGISRest.prototype.getTileGrid);
88042
88043goog.exportProperty(
88044 ol.source.TileArcGISRest.prototype,
88045 'refresh',
88046 ol.source.TileArcGISRest.prototype.refresh);
88047
88048goog.exportProperty(
88049 ol.source.TileArcGISRest.prototype,
88050 'getAttributions',
88051 ol.source.TileArcGISRest.prototype.getAttributions);
88052
88053goog.exportProperty(
88054 ol.source.TileArcGISRest.prototype,
88055 'getLogo',
88056 ol.source.TileArcGISRest.prototype.getLogo);
88057
88058goog.exportProperty(
88059 ol.source.TileArcGISRest.prototype,
88060 'getProjection',
88061 ol.source.TileArcGISRest.prototype.getProjection);
88062
88063goog.exportProperty(
88064 ol.source.TileArcGISRest.prototype,
88065 'getState',
88066 ol.source.TileArcGISRest.prototype.getState);
88067
88068goog.exportProperty(
88069 ol.source.TileArcGISRest.prototype,
88070 'setAttributions',
88071 ol.source.TileArcGISRest.prototype.setAttributions);
88072
88073goog.exportProperty(
88074 ol.source.TileArcGISRest.prototype,
88075 'get',
88076 ol.source.TileArcGISRest.prototype.get);
88077
88078goog.exportProperty(
88079 ol.source.TileArcGISRest.prototype,
88080 'getKeys',
88081 ol.source.TileArcGISRest.prototype.getKeys);
88082
88083goog.exportProperty(
88084 ol.source.TileArcGISRest.prototype,
88085 'getProperties',
88086 ol.source.TileArcGISRest.prototype.getProperties);
88087
88088goog.exportProperty(
88089 ol.source.TileArcGISRest.prototype,
88090 'set',
88091 ol.source.TileArcGISRest.prototype.set);
88092
88093goog.exportProperty(
88094 ol.source.TileArcGISRest.prototype,
88095 'setProperties',
88096 ol.source.TileArcGISRest.prototype.setProperties);
88097
88098goog.exportProperty(
88099 ol.source.TileArcGISRest.prototype,
88100 'unset',
88101 ol.source.TileArcGISRest.prototype.unset);
88102
88103goog.exportProperty(
88104 ol.source.TileArcGISRest.prototype,
88105 'changed',
88106 ol.source.TileArcGISRest.prototype.changed);
88107
88108goog.exportProperty(
88109 ol.source.TileArcGISRest.prototype,
88110 'dispatchEvent',
88111 ol.source.TileArcGISRest.prototype.dispatchEvent);
88112
88113goog.exportProperty(
88114 ol.source.TileArcGISRest.prototype,
88115 'getRevision',
88116 ol.source.TileArcGISRest.prototype.getRevision);
88117
88118goog.exportProperty(
88119 ol.source.TileArcGISRest.prototype,
88120 'on',
88121 ol.source.TileArcGISRest.prototype.on);
88122
88123goog.exportProperty(
88124 ol.source.TileArcGISRest.prototype,
88125 'once',
88126 ol.source.TileArcGISRest.prototype.once);
88127
88128goog.exportProperty(
88129 ol.source.TileArcGISRest.prototype,
88130 'un',
88131 ol.source.TileArcGISRest.prototype.un);
88132
88133goog.exportProperty(
88134 ol.source.TileDebug.prototype,
88135 'getTileGrid',
88136 ol.source.TileDebug.prototype.getTileGrid);
88137
88138goog.exportProperty(
88139 ol.source.TileDebug.prototype,
88140 'refresh',
88141 ol.source.TileDebug.prototype.refresh);
88142
88143goog.exportProperty(
88144 ol.source.TileDebug.prototype,
88145 'getAttributions',
88146 ol.source.TileDebug.prototype.getAttributions);
88147
88148goog.exportProperty(
88149 ol.source.TileDebug.prototype,
88150 'getLogo',
88151 ol.source.TileDebug.prototype.getLogo);
88152
88153goog.exportProperty(
88154 ol.source.TileDebug.prototype,
88155 'getProjection',
88156 ol.source.TileDebug.prototype.getProjection);
88157
88158goog.exportProperty(
88159 ol.source.TileDebug.prototype,
88160 'getState',
88161 ol.source.TileDebug.prototype.getState);
88162
88163goog.exportProperty(
88164 ol.source.TileDebug.prototype,
88165 'setAttributions',
88166 ol.source.TileDebug.prototype.setAttributions);
88167
88168goog.exportProperty(
88169 ol.source.TileDebug.prototype,
88170 'get',
88171 ol.source.TileDebug.prototype.get);
88172
88173goog.exportProperty(
88174 ol.source.TileDebug.prototype,
88175 'getKeys',
88176 ol.source.TileDebug.prototype.getKeys);
88177
88178goog.exportProperty(
88179 ol.source.TileDebug.prototype,
88180 'getProperties',
88181 ol.source.TileDebug.prototype.getProperties);
88182
88183goog.exportProperty(
88184 ol.source.TileDebug.prototype,
88185 'set',
88186 ol.source.TileDebug.prototype.set);
88187
88188goog.exportProperty(
88189 ol.source.TileDebug.prototype,
88190 'setProperties',
88191 ol.source.TileDebug.prototype.setProperties);
88192
88193goog.exportProperty(
88194 ol.source.TileDebug.prototype,
88195 'unset',
88196 ol.source.TileDebug.prototype.unset);
88197
88198goog.exportProperty(
88199 ol.source.TileDebug.prototype,
88200 'changed',
88201 ol.source.TileDebug.prototype.changed);
88202
88203goog.exportProperty(
88204 ol.source.TileDebug.prototype,
88205 'dispatchEvent',
88206 ol.source.TileDebug.prototype.dispatchEvent);
88207
88208goog.exportProperty(
88209 ol.source.TileDebug.prototype,
88210 'getRevision',
88211 ol.source.TileDebug.prototype.getRevision);
88212
88213goog.exportProperty(
88214 ol.source.TileDebug.prototype,
88215 'on',
88216 ol.source.TileDebug.prototype.on);
88217
88218goog.exportProperty(
88219 ol.source.TileDebug.prototype,
88220 'once',
88221 ol.source.TileDebug.prototype.once);
88222
88223goog.exportProperty(
88224 ol.source.TileDebug.prototype,
88225 'un',
88226 ol.source.TileDebug.prototype.un);
88227
88228goog.exportProperty(
88229 ol.source.TileJSON.prototype,
88230 'setRenderReprojectionEdges',
88231 ol.source.TileJSON.prototype.setRenderReprojectionEdges);
88232
88233goog.exportProperty(
88234 ol.source.TileJSON.prototype,
88235 'setTileGridForProjection',
88236 ol.source.TileJSON.prototype.setTileGridForProjection);
88237
88238goog.exportProperty(
88239 ol.source.TileJSON.prototype,
88240 'getTileLoadFunction',
88241 ol.source.TileJSON.prototype.getTileLoadFunction);
88242
88243goog.exportProperty(
88244 ol.source.TileJSON.prototype,
88245 'getTileUrlFunction',
88246 ol.source.TileJSON.prototype.getTileUrlFunction);
88247
88248goog.exportProperty(
88249 ol.source.TileJSON.prototype,
88250 'getUrls',
88251 ol.source.TileJSON.prototype.getUrls);
88252
88253goog.exportProperty(
88254 ol.source.TileJSON.prototype,
88255 'setTileLoadFunction',
88256 ol.source.TileJSON.prototype.setTileLoadFunction);
88257
88258goog.exportProperty(
88259 ol.source.TileJSON.prototype,
88260 'setTileUrlFunction',
88261 ol.source.TileJSON.prototype.setTileUrlFunction);
88262
88263goog.exportProperty(
88264 ol.source.TileJSON.prototype,
88265 'setUrl',
88266 ol.source.TileJSON.prototype.setUrl);
88267
88268goog.exportProperty(
88269 ol.source.TileJSON.prototype,
88270 'setUrls',
88271 ol.source.TileJSON.prototype.setUrls);
88272
88273goog.exportProperty(
88274 ol.source.TileJSON.prototype,
88275 'getTileGrid',
88276 ol.source.TileJSON.prototype.getTileGrid);
88277
88278goog.exportProperty(
88279 ol.source.TileJSON.prototype,
88280 'refresh',
88281 ol.source.TileJSON.prototype.refresh);
88282
88283goog.exportProperty(
88284 ol.source.TileJSON.prototype,
88285 'getAttributions',
88286 ol.source.TileJSON.prototype.getAttributions);
88287
88288goog.exportProperty(
88289 ol.source.TileJSON.prototype,
88290 'getLogo',
88291 ol.source.TileJSON.prototype.getLogo);
88292
88293goog.exportProperty(
88294 ol.source.TileJSON.prototype,
88295 'getProjection',
88296 ol.source.TileJSON.prototype.getProjection);
88297
88298goog.exportProperty(
88299 ol.source.TileJSON.prototype,
88300 'getState',
88301 ol.source.TileJSON.prototype.getState);
88302
88303goog.exportProperty(
88304 ol.source.TileJSON.prototype,
88305 'setAttributions',
88306 ol.source.TileJSON.prototype.setAttributions);
88307
88308goog.exportProperty(
88309 ol.source.TileJSON.prototype,
88310 'get',
88311 ol.source.TileJSON.prototype.get);
88312
88313goog.exportProperty(
88314 ol.source.TileJSON.prototype,
88315 'getKeys',
88316 ol.source.TileJSON.prototype.getKeys);
88317
88318goog.exportProperty(
88319 ol.source.TileJSON.prototype,
88320 'getProperties',
88321 ol.source.TileJSON.prototype.getProperties);
88322
88323goog.exportProperty(
88324 ol.source.TileJSON.prototype,
88325 'set',
88326 ol.source.TileJSON.prototype.set);
88327
88328goog.exportProperty(
88329 ol.source.TileJSON.prototype,
88330 'setProperties',
88331 ol.source.TileJSON.prototype.setProperties);
88332
88333goog.exportProperty(
88334 ol.source.TileJSON.prototype,
88335 'unset',
88336 ol.source.TileJSON.prototype.unset);
88337
88338goog.exportProperty(
88339 ol.source.TileJSON.prototype,
88340 'changed',
88341 ol.source.TileJSON.prototype.changed);
88342
88343goog.exportProperty(
88344 ol.source.TileJSON.prototype,
88345 'dispatchEvent',
88346 ol.source.TileJSON.prototype.dispatchEvent);
88347
88348goog.exportProperty(
88349 ol.source.TileJSON.prototype,
88350 'getRevision',
88351 ol.source.TileJSON.prototype.getRevision);
88352
88353goog.exportProperty(
88354 ol.source.TileJSON.prototype,
88355 'on',
88356 ol.source.TileJSON.prototype.on);
88357
88358goog.exportProperty(
88359 ol.source.TileJSON.prototype,
88360 'once',
88361 ol.source.TileJSON.prototype.once);
88362
88363goog.exportProperty(
88364 ol.source.TileJSON.prototype,
88365 'un',
88366 ol.source.TileJSON.prototype.un);
88367
88368goog.exportProperty(
88369 ol.source.TileUTFGrid.prototype,
88370 'getTileGrid',
88371 ol.source.TileUTFGrid.prototype.getTileGrid);
88372
88373goog.exportProperty(
88374 ol.source.TileUTFGrid.prototype,
88375 'refresh',
88376 ol.source.TileUTFGrid.prototype.refresh);
88377
88378goog.exportProperty(
88379 ol.source.TileUTFGrid.prototype,
88380 'getAttributions',
88381 ol.source.TileUTFGrid.prototype.getAttributions);
88382
88383goog.exportProperty(
88384 ol.source.TileUTFGrid.prototype,
88385 'getLogo',
88386 ol.source.TileUTFGrid.prototype.getLogo);
88387
88388goog.exportProperty(
88389 ol.source.TileUTFGrid.prototype,
88390 'getProjection',
88391 ol.source.TileUTFGrid.prototype.getProjection);
88392
88393goog.exportProperty(
88394 ol.source.TileUTFGrid.prototype,
88395 'getState',
88396 ol.source.TileUTFGrid.prototype.getState);
88397
88398goog.exportProperty(
88399 ol.source.TileUTFGrid.prototype,
88400 'setAttributions',
88401 ol.source.TileUTFGrid.prototype.setAttributions);
88402
88403goog.exportProperty(
88404 ol.source.TileUTFGrid.prototype,
88405 'get',
88406 ol.source.TileUTFGrid.prototype.get);
88407
88408goog.exportProperty(
88409 ol.source.TileUTFGrid.prototype,
88410 'getKeys',
88411 ol.source.TileUTFGrid.prototype.getKeys);
88412
88413goog.exportProperty(
88414 ol.source.TileUTFGrid.prototype,
88415 'getProperties',
88416 ol.source.TileUTFGrid.prototype.getProperties);
88417
88418goog.exportProperty(
88419 ol.source.TileUTFGrid.prototype,
88420 'set',
88421 ol.source.TileUTFGrid.prototype.set);
88422
88423goog.exportProperty(
88424 ol.source.TileUTFGrid.prototype,
88425 'setProperties',
88426 ol.source.TileUTFGrid.prototype.setProperties);
88427
88428goog.exportProperty(
88429 ol.source.TileUTFGrid.prototype,
88430 'unset',
88431 ol.source.TileUTFGrid.prototype.unset);
88432
88433goog.exportProperty(
88434 ol.source.TileUTFGrid.prototype,
88435 'changed',
88436 ol.source.TileUTFGrid.prototype.changed);
88437
88438goog.exportProperty(
88439 ol.source.TileUTFGrid.prototype,
88440 'dispatchEvent',
88441 ol.source.TileUTFGrid.prototype.dispatchEvent);
88442
88443goog.exportProperty(
88444 ol.source.TileUTFGrid.prototype,
88445 'getRevision',
88446 ol.source.TileUTFGrid.prototype.getRevision);
88447
88448goog.exportProperty(
88449 ol.source.TileUTFGrid.prototype,
88450 'on',
88451 ol.source.TileUTFGrid.prototype.on);
88452
88453goog.exportProperty(
88454 ol.source.TileUTFGrid.prototype,
88455 'once',
88456 ol.source.TileUTFGrid.prototype.once);
88457
88458goog.exportProperty(
88459 ol.source.TileUTFGrid.prototype,
88460 'un',
88461 ol.source.TileUTFGrid.prototype.un);
88462
88463goog.exportProperty(
88464 ol.source.TileWMS.prototype,
88465 'setRenderReprojectionEdges',
88466 ol.source.TileWMS.prototype.setRenderReprojectionEdges);
88467
88468goog.exportProperty(
88469 ol.source.TileWMS.prototype,
88470 'setTileGridForProjection',
88471 ol.source.TileWMS.prototype.setTileGridForProjection);
88472
88473goog.exportProperty(
88474 ol.source.TileWMS.prototype,
88475 'getTileLoadFunction',
88476 ol.source.TileWMS.prototype.getTileLoadFunction);
88477
88478goog.exportProperty(
88479 ol.source.TileWMS.prototype,
88480 'getTileUrlFunction',
88481 ol.source.TileWMS.prototype.getTileUrlFunction);
88482
88483goog.exportProperty(
88484 ol.source.TileWMS.prototype,
88485 'getUrls',
88486 ol.source.TileWMS.prototype.getUrls);
88487
88488goog.exportProperty(
88489 ol.source.TileWMS.prototype,
88490 'setTileLoadFunction',
88491 ol.source.TileWMS.prototype.setTileLoadFunction);
88492
88493goog.exportProperty(
88494 ol.source.TileWMS.prototype,
88495 'setTileUrlFunction',
88496 ol.source.TileWMS.prototype.setTileUrlFunction);
88497
88498goog.exportProperty(
88499 ol.source.TileWMS.prototype,
88500 'setUrl',
88501 ol.source.TileWMS.prototype.setUrl);
88502
88503goog.exportProperty(
88504 ol.source.TileWMS.prototype,
88505 'setUrls',
88506 ol.source.TileWMS.prototype.setUrls);
88507
88508goog.exportProperty(
88509 ol.source.TileWMS.prototype,
88510 'getTileGrid',
88511 ol.source.TileWMS.prototype.getTileGrid);
88512
88513goog.exportProperty(
88514 ol.source.TileWMS.prototype,
88515 'refresh',
88516 ol.source.TileWMS.prototype.refresh);
88517
88518goog.exportProperty(
88519 ol.source.TileWMS.prototype,
88520 'getAttributions',
88521 ol.source.TileWMS.prototype.getAttributions);
88522
88523goog.exportProperty(
88524 ol.source.TileWMS.prototype,
88525 'getLogo',
88526 ol.source.TileWMS.prototype.getLogo);
88527
88528goog.exportProperty(
88529 ol.source.TileWMS.prototype,
88530 'getProjection',
88531 ol.source.TileWMS.prototype.getProjection);
88532
88533goog.exportProperty(
88534 ol.source.TileWMS.prototype,
88535 'getState',
88536 ol.source.TileWMS.prototype.getState);
88537
88538goog.exportProperty(
88539 ol.source.TileWMS.prototype,
88540 'setAttributions',
88541 ol.source.TileWMS.prototype.setAttributions);
88542
88543goog.exportProperty(
88544 ol.source.TileWMS.prototype,
88545 'get',
88546 ol.source.TileWMS.prototype.get);
88547
88548goog.exportProperty(
88549 ol.source.TileWMS.prototype,
88550 'getKeys',
88551 ol.source.TileWMS.prototype.getKeys);
88552
88553goog.exportProperty(
88554 ol.source.TileWMS.prototype,
88555 'getProperties',
88556 ol.source.TileWMS.prototype.getProperties);
88557
88558goog.exportProperty(
88559 ol.source.TileWMS.prototype,
88560 'set',
88561 ol.source.TileWMS.prototype.set);
88562
88563goog.exportProperty(
88564 ol.source.TileWMS.prototype,
88565 'setProperties',
88566 ol.source.TileWMS.prototype.setProperties);
88567
88568goog.exportProperty(
88569 ol.source.TileWMS.prototype,
88570 'unset',
88571 ol.source.TileWMS.prototype.unset);
88572
88573goog.exportProperty(
88574 ol.source.TileWMS.prototype,
88575 'changed',
88576 ol.source.TileWMS.prototype.changed);
88577
88578goog.exportProperty(
88579 ol.source.TileWMS.prototype,
88580 'dispatchEvent',
88581 ol.source.TileWMS.prototype.dispatchEvent);
88582
88583goog.exportProperty(
88584 ol.source.TileWMS.prototype,
88585 'getRevision',
88586 ol.source.TileWMS.prototype.getRevision);
88587
88588goog.exportProperty(
88589 ol.source.TileWMS.prototype,
88590 'on',
88591 ol.source.TileWMS.prototype.on);
88592
88593goog.exportProperty(
88594 ol.source.TileWMS.prototype,
88595 'once',
88596 ol.source.TileWMS.prototype.once);
88597
88598goog.exportProperty(
88599 ol.source.TileWMS.prototype,
88600 'un',
88601 ol.source.TileWMS.prototype.un);
88602
88603goog.exportProperty(
88604 ol.source.Vector.Event.prototype,
88605 'type',
88606 ol.source.Vector.Event.prototype.type);
88607
88608goog.exportProperty(
88609 ol.source.Vector.Event.prototype,
88610 'target',
88611 ol.source.Vector.Event.prototype.target);
88612
88613goog.exportProperty(
88614 ol.source.Vector.Event.prototype,
88615 'preventDefault',
88616 ol.source.Vector.Event.prototype.preventDefault);
88617
88618goog.exportProperty(
88619 ol.source.Vector.Event.prototype,
88620 'stopPropagation',
88621 ol.source.Vector.Event.prototype.stopPropagation);
88622
88623goog.exportProperty(
88624 ol.source.VectorTile.prototype,
88625 'getTileLoadFunction',
88626 ol.source.VectorTile.prototype.getTileLoadFunction);
88627
88628goog.exportProperty(
88629 ol.source.VectorTile.prototype,
88630 'getTileUrlFunction',
88631 ol.source.VectorTile.prototype.getTileUrlFunction);
88632
88633goog.exportProperty(
88634 ol.source.VectorTile.prototype,
88635 'getUrls',
88636 ol.source.VectorTile.prototype.getUrls);
88637
88638goog.exportProperty(
88639 ol.source.VectorTile.prototype,
88640 'setTileLoadFunction',
88641 ol.source.VectorTile.prototype.setTileLoadFunction);
88642
88643goog.exportProperty(
88644 ol.source.VectorTile.prototype,
88645 'setTileUrlFunction',
88646 ol.source.VectorTile.prototype.setTileUrlFunction);
88647
88648goog.exportProperty(
88649 ol.source.VectorTile.prototype,
88650 'setUrl',
88651 ol.source.VectorTile.prototype.setUrl);
88652
88653goog.exportProperty(
88654 ol.source.VectorTile.prototype,
88655 'setUrls',
88656 ol.source.VectorTile.prototype.setUrls);
88657
88658goog.exportProperty(
88659 ol.source.VectorTile.prototype,
88660 'getTileGrid',
88661 ol.source.VectorTile.prototype.getTileGrid);
88662
88663goog.exportProperty(
88664 ol.source.VectorTile.prototype,
88665 'refresh',
88666 ol.source.VectorTile.prototype.refresh);
88667
88668goog.exportProperty(
88669 ol.source.VectorTile.prototype,
88670 'getAttributions',
88671 ol.source.VectorTile.prototype.getAttributions);
88672
88673goog.exportProperty(
88674 ol.source.VectorTile.prototype,
88675 'getLogo',
88676 ol.source.VectorTile.prototype.getLogo);
88677
88678goog.exportProperty(
88679 ol.source.VectorTile.prototype,
88680 'getProjection',
88681 ol.source.VectorTile.prototype.getProjection);
88682
88683goog.exportProperty(
88684 ol.source.VectorTile.prototype,
88685 'getState',
88686 ol.source.VectorTile.prototype.getState);
88687
88688goog.exportProperty(
88689 ol.source.VectorTile.prototype,
88690 'setAttributions',
88691 ol.source.VectorTile.prototype.setAttributions);
88692
88693goog.exportProperty(
88694 ol.source.VectorTile.prototype,
88695 'get',
88696 ol.source.VectorTile.prototype.get);
88697
88698goog.exportProperty(
88699 ol.source.VectorTile.prototype,
88700 'getKeys',
88701 ol.source.VectorTile.prototype.getKeys);
88702
88703goog.exportProperty(
88704 ol.source.VectorTile.prototype,
88705 'getProperties',
88706 ol.source.VectorTile.prototype.getProperties);
88707
88708goog.exportProperty(
88709 ol.source.VectorTile.prototype,
88710 'set',
88711 ol.source.VectorTile.prototype.set);
88712
88713goog.exportProperty(
88714 ol.source.VectorTile.prototype,
88715 'setProperties',
88716 ol.source.VectorTile.prototype.setProperties);
88717
88718goog.exportProperty(
88719 ol.source.VectorTile.prototype,
88720 'unset',
88721 ol.source.VectorTile.prototype.unset);
88722
88723goog.exportProperty(
88724 ol.source.VectorTile.prototype,
88725 'changed',
88726 ol.source.VectorTile.prototype.changed);
88727
88728goog.exportProperty(
88729 ol.source.VectorTile.prototype,
88730 'dispatchEvent',
88731 ol.source.VectorTile.prototype.dispatchEvent);
88732
88733goog.exportProperty(
88734 ol.source.VectorTile.prototype,
88735 'getRevision',
88736 ol.source.VectorTile.prototype.getRevision);
88737
88738goog.exportProperty(
88739 ol.source.VectorTile.prototype,
88740 'on',
88741 ol.source.VectorTile.prototype.on);
88742
88743goog.exportProperty(
88744 ol.source.VectorTile.prototype,
88745 'once',
88746 ol.source.VectorTile.prototype.once);
88747
88748goog.exportProperty(
88749 ol.source.VectorTile.prototype,
88750 'un',
88751 ol.source.VectorTile.prototype.un);
88752
88753goog.exportProperty(
88754 ol.source.WMTS.prototype,
88755 'setRenderReprojectionEdges',
88756 ol.source.WMTS.prototype.setRenderReprojectionEdges);
88757
88758goog.exportProperty(
88759 ol.source.WMTS.prototype,
88760 'setTileGridForProjection',
88761 ol.source.WMTS.prototype.setTileGridForProjection);
88762
88763goog.exportProperty(
88764 ol.source.WMTS.prototype,
88765 'getTileLoadFunction',
88766 ol.source.WMTS.prototype.getTileLoadFunction);
88767
88768goog.exportProperty(
88769 ol.source.WMTS.prototype,
88770 'getTileUrlFunction',
88771 ol.source.WMTS.prototype.getTileUrlFunction);
88772
88773goog.exportProperty(
88774 ol.source.WMTS.prototype,
88775 'getUrls',
88776 ol.source.WMTS.prototype.getUrls);
88777
88778goog.exportProperty(
88779 ol.source.WMTS.prototype,
88780 'setTileLoadFunction',
88781 ol.source.WMTS.prototype.setTileLoadFunction);
88782
88783goog.exportProperty(
88784 ol.source.WMTS.prototype,
88785 'setTileUrlFunction',
88786 ol.source.WMTS.prototype.setTileUrlFunction);
88787
88788goog.exportProperty(
88789 ol.source.WMTS.prototype,
88790 'setUrl',
88791 ol.source.WMTS.prototype.setUrl);
88792
88793goog.exportProperty(
88794 ol.source.WMTS.prototype,
88795 'setUrls',
88796 ol.source.WMTS.prototype.setUrls);
88797
88798goog.exportProperty(
88799 ol.source.WMTS.prototype,
88800 'getTileGrid',
88801 ol.source.WMTS.prototype.getTileGrid);
88802
88803goog.exportProperty(
88804 ol.source.WMTS.prototype,
88805 'refresh',
88806 ol.source.WMTS.prototype.refresh);
88807
88808goog.exportProperty(
88809 ol.source.WMTS.prototype,
88810 'getAttributions',
88811 ol.source.WMTS.prototype.getAttributions);
88812
88813goog.exportProperty(
88814 ol.source.WMTS.prototype,
88815 'getLogo',
88816 ol.source.WMTS.prototype.getLogo);
88817
88818goog.exportProperty(
88819 ol.source.WMTS.prototype,
88820 'getProjection',
88821 ol.source.WMTS.prototype.getProjection);
88822
88823goog.exportProperty(
88824 ol.source.WMTS.prototype,
88825 'getState',
88826 ol.source.WMTS.prototype.getState);
88827
88828goog.exportProperty(
88829 ol.source.WMTS.prototype,
88830 'setAttributions',
88831 ol.source.WMTS.prototype.setAttributions);
88832
88833goog.exportProperty(
88834 ol.source.WMTS.prototype,
88835 'get',
88836 ol.source.WMTS.prototype.get);
88837
88838goog.exportProperty(
88839 ol.source.WMTS.prototype,
88840 'getKeys',
88841 ol.source.WMTS.prototype.getKeys);
88842
88843goog.exportProperty(
88844 ol.source.WMTS.prototype,
88845 'getProperties',
88846 ol.source.WMTS.prototype.getProperties);
88847
88848goog.exportProperty(
88849 ol.source.WMTS.prototype,
88850 'set',
88851 ol.source.WMTS.prototype.set);
88852
88853goog.exportProperty(
88854 ol.source.WMTS.prototype,
88855 'setProperties',
88856 ol.source.WMTS.prototype.setProperties);
88857
88858goog.exportProperty(
88859 ol.source.WMTS.prototype,
88860 'unset',
88861 ol.source.WMTS.prototype.unset);
88862
88863goog.exportProperty(
88864 ol.source.WMTS.prototype,
88865 'changed',
88866 ol.source.WMTS.prototype.changed);
88867
88868goog.exportProperty(
88869 ol.source.WMTS.prototype,
88870 'dispatchEvent',
88871 ol.source.WMTS.prototype.dispatchEvent);
88872
88873goog.exportProperty(
88874 ol.source.WMTS.prototype,
88875 'getRevision',
88876 ol.source.WMTS.prototype.getRevision);
88877
88878goog.exportProperty(
88879 ol.source.WMTS.prototype,
88880 'on',
88881 ol.source.WMTS.prototype.on);
88882
88883goog.exportProperty(
88884 ol.source.WMTS.prototype,
88885 'once',
88886 ol.source.WMTS.prototype.once);
88887
88888goog.exportProperty(
88889 ol.source.WMTS.prototype,
88890 'un',
88891 ol.source.WMTS.prototype.un);
88892
88893goog.exportProperty(
88894 ol.source.Zoomify.prototype,
88895 'setRenderReprojectionEdges',
88896 ol.source.Zoomify.prototype.setRenderReprojectionEdges);
88897
88898goog.exportProperty(
88899 ol.source.Zoomify.prototype,
88900 'setTileGridForProjection',
88901 ol.source.Zoomify.prototype.setTileGridForProjection);
88902
88903goog.exportProperty(
88904 ol.source.Zoomify.prototype,
88905 'getTileLoadFunction',
88906 ol.source.Zoomify.prototype.getTileLoadFunction);
88907
88908goog.exportProperty(
88909 ol.source.Zoomify.prototype,
88910 'getTileUrlFunction',
88911 ol.source.Zoomify.prototype.getTileUrlFunction);
88912
88913goog.exportProperty(
88914 ol.source.Zoomify.prototype,
88915 'getUrls',
88916 ol.source.Zoomify.prototype.getUrls);
88917
88918goog.exportProperty(
88919 ol.source.Zoomify.prototype,
88920 'setTileLoadFunction',
88921 ol.source.Zoomify.prototype.setTileLoadFunction);
88922
88923goog.exportProperty(
88924 ol.source.Zoomify.prototype,
88925 'setTileUrlFunction',
88926 ol.source.Zoomify.prototype.setTileUrlFunction);
88927
88928goog.exportProperty(
88929 ol.source.Zoomify.prototype,
88930 'setUrl',
88931 ol.source.Zoomify.prototype.setUrl);
88932
88933goog.exportProperty(
88934 ol.source.Zoomify.prototype,
88935 'setUrls',
88936 ol.source.Zoomify.prototype.setUrls);
88937
88938goog.exportProperty(
88939 ol.source.Zoomify.prototype,
88940 'getTileGrid',
88941 ol.source.Zoomify.prototype.getTileGrid);
88942
88943goog.exportProperty(
88944 ol.source.Zoomify.prototype,
88945 'refresh',
88946 ol.source.Zoomify.prototype.refresh);
88947
88948goog.exportProperty(
88949 ol.source.Zoomify.prototype,
88950 'getAttributions',
88951 ol.source.Zoomify.prototype.getAttributions);
88952
88953goog.exportProperty(
88954 ol.source.Zoomify.prototype,
88955 'getLogo',
88956 ol.source.Zoomify.prototype.getLogo);
88957
88958goog.exportProperty(
88959 ol.source.Zoomify.prototype,
88960 'getProjection',
88961 ol.source.Zoomify.prototype.getProjection);
88962
88963goog.exportProperty(
88964 ol.source.Zoomify.prototype,
88965 'getState',
88966 ol.source.Zoomify.prototype.getState);
88967
88968goog.exportProperty(
88969 ol.source.Zoomify.prototype,
88970 'setAttributions',
88971 ol.source.Zoomify.prototype.setAttributions);
88972
88973goog.exportProperty(
88974 ol.source.Zoomify.prototype,
88975 'get',
88976 ol.source.Zoomify.prototype.get);
88977
88978goog.exportProperty(
88979 ol.source.Zoomify.prototype,
88980 'getKeys',
88981 ol.source.Zoomify.prototype.getKeys);
88982
88983goog.exportProperty(
88984 ol.source.Zoomify.prototype,
88985 'getProperties',
88986 ol.source.Zoomify.prototype.getProperties);
88987
88988goog.exportProperty(
88989 ol.source.Zoomify.prototype,
88990 'set',
88991 ol.source.Zoomify.prototype.set);
88992
88993goog.exportProperty(
88994 ol.source.Zoomify.prototype,
88995 'setProperties',
88996 ol.source.Zoomify.prototype.setProperties);
88997
88998goog.exportProperty(
88999 ol.source.Zoomify.prototype,
89000 'unset',
89001 ol.source.Zoomify.prototype.unset);
89002
89003goog.exportProperty(
89004 ol.source.Zoomify.prototype,
89005 'changed',
89006 ol.source.Zoomify.prototype.changed);
89007
89008goog.exportProperty(
89009 ol.source.Zoomify.prototype,
89010 'dispatchEvent',
89011 ol.source.Zoomify.prototype.dispatchEvent);
89012
89013goog.exportProperty(
89014 ol.source.Zoomify.prototype,
89015 'getRevision',
89016 ol.source.Zoomify.prototype.getRevision);
89017
89018goog.exportProperty(
89019 ol.source.Zoomify.prototype,
89020 'on',
89021 ol.source.Zoomify.prototype.on);
89022
89023goog.exportProperty(
89024 ol.source.Zoomify.prototype,
89025 'once',
89026 ol.source.Zoomify.prototype.once);
89027
89028goog.exportProperty(
89029 ol.source.Zoomify.prototype,
89030 'un',
89031 ol.source.Zoomify.prototype.un);
89032
89033goog.exportProperty(
89034 ol.reproj.Tile.prototype,
89035 'getTileCoord',
89036 ol.reproj.Tile.prototype.getTileCoord);
89037
89038goog.exportProperty(
89039 ol.reproj.Tile.prototype,
89040 'load',
89041 ol.reproj.Tile.prototype.load);
89042
89043goog.exportProperty(
89044 ol.renderer.Layer.prototype,
89045 'changed',
89046 ol.renderer.Layer.prototype.changed);
89047
89048goog.exportProperty(
89049 ol.renderer.Layer.prototype,
89050 'dispatchEvent',
89051 ol.renderer.Layer.prototype.dispatchEvent);
89052
89053goog.exportProperty(
89054 ol.renderer.Layer.prototype,
89055 'getRevision',
89056 ol.renderer.Layer.prototype.getRevision);
89057
89058goog.exportProperty(
89059 ol.renderer.Layer.prototype,
89060 'on',
89061 ol.renderer.Layer.prototype.on);
89062
89063goog.exportProperty(
89064 ol.renderer.Layer.prototype,
89065 'once',
89066 ol.renderer.Layer.prototype.once);
89067
89068goog.exportProperty(
89069 ol.renderer.Layer.prototype,
89070 'un',
89071 ol.renderer.Layer.prototype.un);
89072
89073goog.exportProperty(
89074 ol.renderer.webgl.Layer.prototype,
89075 'changed',
89076 ol.renderer.webgl.Layer.prototype.changed);
89077
89078goog.exportProperty(
89079 ol.renderer.webgl.Layer.prototype,
89080 'dispatchEvent',
89081 ol.renderer.webgl.Layer.prototype.dispatchEvent);
89082
89083goog.exportProperty(
89084 ol.renderer.webgl.Layer.prototype,
89085 'getRevision',
89086 ol.renderer.webgl.Layer.prototype.getRevision);
89087
89088goog.exportProperty(
89089 ol.renderer.webgl.Layer.prototype,
89090 'on',
89091 ol.renderer.webgl.Layer.prototype.on);
89092
89093goog.exportProperty(
89094 ol.renderer.webgl.Layer.prototype,
89095 'once',
89096 ol.renderer.webgl.Layer.prototype.once);
89097
89098goog.exportProperty(
89099 ol.renderer.webgl.Layer.prototype,
89100 'un',
89101 ol.renderer.webgl.Layer.prototype.un);
89102
89103goog.exportProperty(
89104 ol.renderer.webgl.ImageLayer.prototype,
89105 'changed',
89106 ol.renderer.webgl.ImageLayer.prototype.changed);
89107
89108goog.exportProperty(
89109 ol.renderer.webgl.ImageLayer.prototype,
89110 'dispatchEvent',
89111 ol.renderer.webgl.ImageLayer.prototype.dispatchEvent);
89112
89113goog.exportProperty(
89114 ol.renderer.webgl.ImageLayer.prototype,
89115 'getRevision',
89116 ol.renderer.webgl.ImageLayer.prototype.getRevision);
89117
89118goog.exportProperty(
89119 ol.renderer.webgl.ImageLayer.prototype,
89120 'on',
89121 ol.renderer.webgl.ImageLayer.prototype.on);
89122
89123goog.exportProperty(
89124 ol.renderer.webgl.ImageLayer.prototype,
89125 'once',
89126 ol.renderer.webgl.ImageLayer.prototype.once);
89127
89128goog.exportProperty(
89129 ol.renderer.webgl.ImageLayer.prototype,
89130 'un',
89131 ol.renderer.webgl.ImageLayer.prototype.un);
89132
89133goog.exportProperty(
89134 ol.renderer.webgl.TileLayer.prototype,
89135 'changed',
89136 ol.renderer.webgl.TileLayer.prototype.changed);
89137
89138goog.exportProperty(
89139 ol.renderer.webgl.TileLayer.prototype,
89140 'dispatchEvent',
89141 ol.renderer.webgl.TileLayer.prototype.dispatchEvent);
89142
89143goog.exportProperty(
89144 ol.renderer.webgl.TileLayer.prototype,
89145 'getRevision',
89146 ol.renderer.webgl.TileLayer.prototype.getRevision);
89147
89148goog.exportProperty(
89149 ol.renderer.webgl.TileLayer.prototype,
89150 'on',
89151 ol.renderer.webgl.TileLayer.prototype.on);
89152
89153goog.exportProperty(
89154 ol.renderer.webgl.TileLayer.prototype,
89155 'once',
89156 ol.renderer.webgl.TileLayer.prototype.once);
89157
89158goog.exportProperty(
89159 ol.renderer.webgl.TileLayer.prototype,
89160 'un',
89161 ol.renderer.webgl.TileLayer.prototype.un);
89162
89163goog.exportProperty(
89164 ol.renderer.webgl.VectorLayer.prototype,
89165 'changed',
89166 ol.renderer.webgl.VectorLayer.prototype.changed);
89167
89168goog.exportProperty(
89169 ol.renderer.webgl.VectorLayer.prototype,
89170 'dispatchEvent',
89171 ol.renderer.webgl.VectorLayer.prototype.dispatchEvent);
89172
89173goog.exportProperty(
89174 ol.renderer.webgl.VectorLayer.prototype,
89175 'getRevision',
89176 ol.renderer.webgl.VectorLayer.prototype.getRevision);
89177
89178goog.exportProperty(
89179 ol.renderer.webgl.VectorLayer.prototype,
89180 'on',
89181 ol.renderer.webgl.VectorLayer.prototype.on);
89182
89183goog.exportProperty(
89184 ol.renderer.webgl.VectorLayer.prototype,
89185 'once',
89186 ol.renderer.webgl.VectorLayer.prototype.once);
89187
89188goog.exportProperty(
89189 ol.renderer.webgl.VectorLayer.prototype,
89190 'un',
89191 ol.renderer.webgl.VectorLayer.prototype.un);
89192
89193goog.exportProperty(
89194 ol.renderer.canvas.Layer.prototype,
89195 'changed',
89196 ol.renderer.canvas.Layer.prototype.changed);
89197
89198goog.exportProperty(
89199 ol.renderer.canvas.Layer.prototype,
89200 'dispatchEvent',
89201 ol.renderer.canvas.Layer.prototype.dispatchEvent);
89202
89203goog.exportProperty(
89204 ol.renderer.canvas.Layer.prototype,
89205 'getRevision',
89206 ol.renderer.canvas.Layer.prototype.getRevision);
89207
89208goog.exportProperty(
89209 ol.renderer.canvas.Layer.prototype,
89210 'on',
89211 ol.renderer.canvas.Layer.prototype.on);
89212
89213goog.exportProperty(
89214 ol.renderer.canvas.Layer.prototype,
89215 'once',
89216 ol.renderer.canvas.Layer.prototype.once);
89217
89218goog.exportProperty(
89219 ol.renderer.canvas.Layer.prototype,
89220 'un',
89221 ol.renderer.canvas.Layer.prototype.un);
89222
89223goog.exportProperty(
89224 ol.renderer.canvas.IntermediateCanvas.prototype,
89225 'changed',
89226 ol.renderer.canvas.IntermediateCanvas.prototype.changed);
89227
89228goog.exportProperty(
89229 ol.renderer.canvas.IntermediateCanvas.prototype,
89230 'dispatchEvent',
89231 ol.renderer.canvas.IntermediateCanvas.prototype.dispatchEvent);
89232
89233goog.exportProperty(
89234 ol.renderer.canvas.IntermediateCanvas.prototype,
89235 'getRevision',
89236 ol.renderer.canvas.IntermediateCanvas.prototype.getRevision);
89237
89238goog.exportProperty(
89239 ol.renderer.canvas.IntermediateCanvas.prototype,
89240 'on',
89241 ol.renderer.canvas.IntermediateCanvas.prototype.on);
89242
89243goog.exportProperty(
89244 ol.renderer.canvas.IntermediateCanvas.prototype,
89245 'once',
89246 ol.renderer.canvas.IntermediateCanvas.prototype.once);
89247
89248goog.exportProperty(
89249 ol.renderer.canvas.IntermediateCanvas.prototype,
89250 'un',
89251 ol.renderer.canvas.IntermediateCanvas.prototype.un);
89252
89253goog.exportProperty(
89254 ol.renderer.canvas.ImageLayer.prototype,
89255 'changed',
89256 ol.renderer.canvas.ImageLayer.prototype.changed);
89257
89258goog.exportProperty(
89259 ol.renderer.canvas.ImageLayer.prototype,
89260 'dispatchEvent',
89261 ol.renderer.canvas.ImageLayer.prototype.dispatchEvent);
89262
89263goog.exportProperty(
89264 ol.renderer.canvas.ImageLayer.prototype,
89265 'getRevision',
89266 ol.renderer.canvas.ImageLayer.prototype.getRevision);
89267
89268goog.exportProperty(
89269 ol.renderer.canvas.ImageLayer.prototype,
89270 'on',
89271 ol.renderer.canvas.ImageLayer.prototype.on);
89272
89273goog.exportProperty(
89274 ol.renderer.canvas.ImageLayer.prototype,
89275 'once',
89276 ol.renderer.canvas.ImageLayer.prototype.once);
89277
89278goog.exportProperty(
89279 ol.renderer.canvas.ImageLayer.prototype,
89280 'un',
89281 ol.renderer.canvas.ImageLayer.prototype.un);
89282
89283goog.exportProperty(
89284 ol.renderer.canvas.TileLayer.prototype,
89285 'changed',
89286 ol.renderer.canvas.TileLayer.prototype.changed);
89287
89288goog.exportProperty(
89289 ol.renderer.canvas.TileLayer.prototype,
89290 'dispatchEvent',
89291 ol.renderer.canvas.TileLayer.prototype.dispatchEvent);
89292
89293goog.exportProperty(
89294 ol.renderer.canvas.TileLayer.prototype,
89295 'getRevision',
89296 ol.renderer.canvas.TileLayer.prototype.getRevision);
89297
89298goog.exportProperty(
89299 ol.renderer.canvas.TileLayer.prototype,
89300 'on',
89301 ol.renderer.canvas.TileLayer.prototype.on);
89302
89303goog.exportProperty(
89304 ol.renderer.canvas.TileLayer.prototype,
89305 'once',
89306 ol.renderer.canvas.TileLayer.prototype.once);
89307
89308goog.exportProperty(
89309 ol.renderer.canvas.TileLayer.prototype,
89310 'un',
89311 ol.renderer.canvas.TileLayer.prototype.un);
89312
89313goog.exportProperty(
89314 ol.renderer.canvas.VectorLayer.prototype,
89315 'changed',
89316 ol.renderer.canvas.VectorLayer.prototype.changed);
89317
89318goog.exportProperty(
89319 ol.renderer.canvas.VectorLayer.prototype,
89320 'dispatchEvent',
89321 ol.renderer.canvas.VectorLayer.prototype.dispatchEvent);
89322
89323goog.exportProperty(
89324 ol.renderer.canvas.VectorLayer.prototype,
89325 'getRevision',
89326 ol.renderer.canvas.VectorLayer.prototype.getRevision);
89327
89328goog.exportProperty(
89329 ol.renderer.canvas.VectorLayer.prototype,
89330 'on',
89331 ol.renderer.canvas.VectorLayer.prototype.on);
89332
89333goog.exportProperty(
89334 ol.renderer.canvas.VectorLayer.prototype,
89335 'once',
89336 ol.renderer.canvas.VectorLayer.prototype.once);
89337
89338goog.exportProperty(
89339 ol.renderer.canvas.VectorLayer.prototype,
89340 'un',
89341 ol.renderer.canvas.VectorLayer.prototype.un);
89342
89343goog.exportProperty(
89344 ol.renderer.canvas.VectorTileLayer.prototype,
89345 'changed',
89346 ol.renderer.canvas.VectorTileLayer.prototype.changed);
89347
89348goog.exportProperty(
89349 ol.renderer.canvas.VectorTileLayer.prototype,
89350 'dispatchEvent',
89351 ol.renderer.canvas.VectorTileLayer.prototype.dispatchEvent);
89352
89353goog.exportProperty(
89354 ol.renderer.canvas.VectorTileLayer.prototype,
89355 'getRevision',
89356 ol.renderer.canvas.VectorTileLayer.prototype.getRevision);
89357
89358goog.exportProperty(
89359 ol.renderer.canvas.VectorTileLayer.prototype,
89360 'on',
89361 ol.renderer.canvas.VectorTileLayer.prototype.on);
89362
89363goog.exportProperty(
89364 ol.renderer.canvas.VectorTileLayer.prototype,
89365 'once',
89366 ol.renderer.canvas.VectorTileLayer.prototype.once);
89367
89368goog.exportProperty(
89369 ol.renderer.canvas.VectorTileLayer.prototype,
89370 'un',
89371 ol.renderer.canvas.VectorTileLayer.prototype.un);
89372
89373goog.exportProperty(
89374 ol.render.Event.prototype,
89375 'type',
89376 ol.render.Event.prototype.type);
89377
89378goog.exportProperty(
89379 ol.render.Event.prototype,
89380 'target',
89381 ol.render.Event.prototype.target);
89382
89383goog.exportProperty(
89384 ol.render.Event.prototype,
89385 'preventDefault',
89386 ol.render.Event.prototype.preventDefault);
89387
89388goog.exportProperty(
89389 ol.render.Event.prototype,
89390 'stopPropagation',
89391 ol.render.Event.prototype.stopPropagation);
89392
89393goog.exportProperty(
89394 ol.pointer.PointerEvent.prototype,
89395 'type',
89396 ol.pointer.PointerEvent.prototype.type);
89397
89398goog.exportProperty(
89399 ol.pointer.PointerEvent.prototype,
89400 'target',
89401 ol.pointer.PointerEvent.prototype.target);
89402
89403goog.exportProperty(
89404 ol.pointer.PointerEvent.prototype,
89405 'preventDefault',
89406 ol.pointer.PointerEvent.prototype.preventDefault);
89407
89408goog.exportProperty(
89409 ol.pointer.PointerEvent.prototype,
89410 'stopPropagation',
89411 ol.pointer.PointerEvent.prototype.stopPropagation);
89412
89413goog.exportProperty(
89414 ol.layer.Base.prototype,
89415 'get',
89416 ol.layer.Base.prototype.get);
89417
89418goog.exportProperty(
89419 ol.layer.Base.prototype,
89420 'getKeys',
89421 ol.layer.Base.prototype.getKeys);
89422
89423goog.exportProperty(
89424 ol.layer.Base.prototype,
89425 'getProperties',
89426 ol.layer.Base.prototype.getProperties);
89427
89428goog.exportProperty(
89429 ol.layer.Base.prototype,
89430 'set',
89431 ol.layer.Base.prototype.set);
89432
89433goog.exportProperty(
89434 ol.layer.Base.prototype,
89435 'setProperties',
89436 ol.layer.Base.prototype.setProperties);
89437
89438goog.exportProperty(
89439 ol.layer.Base.prototype,
89440 'unset',
89441 ol.layer.Base.prototype.unset);
89442
89443goog.exportProperty(
89444 ol.layer.Base.prototype,
89445 'changed',
89446 ol.layer.Base.prototype.changed);
89447
89448goog.exportProperty(
89449 ol.layer.Base.prototype,
89450 'dispatchEvent',
89451 ol.layer.Base.prototype.dispatchEvent);
89452
89453goog.exportProperty(
89454 ol.layer.Base.prototype,
89455 'getRevision',
89456 ol.layer.Base.prototype.getRevision);
89457
89458goog.exportProperty(
89459 ol.layer.Base.prototype,
89460 'on',
89461 ol.layer.Base.prototype.on);
89462
89463goog.exportProperty(
89464 ol.layer.Base.prototype,
89465 'once',
89466 ol.layer.Base.prototype.once);
89467
89468goog.exportProperty(
89469 ol.layer.Base.prototype,
89470 'un',
89471 ol.layer.Base.prototype.un);
89472
89473goog.exportProperty(
89474 ol.layer.Group.prototype,
89475 'getExtent',
89476 ol.layer.Group.prototype.getExtent);
89477
89478goog.exportProperty(
89479 ol.layer.Group.prototype,
89480 'getMaxResolution',
89481 ol.layer.Group.prototype.getMaxResolution);
89482
89483goog.exportProperty(
89484 ol.layer.Group.prototype,
89485 'getMinResolution',
89486 ol.layer.Group.prototype.getMinResolution);
89487
89488goog.exportProperty(
89489 ol.layer.Group.prototype,
89490 'getOpacity',
89491 ol.layer.Group.prototype.getOpacity);
89492
89493goog.exportProperty(
89494 ol.layer.Group.prototype,
89495 'getVisible',
89496 ol.layer.Group.prototype.getVisible);
89497
89498goog.exportProperty(
89499 ol.layer.Group.prototype,
89500 'getZIndex',
89501 ol.layer.Group.prototype.getZIndex);
89502
89503goog.exportProperty(
89504 ol.layer.Group.prototype,
89505 'setExtent',
89506 ol.layer.Group.prototype.setExtent);
89507
89508goog.exportProperty(
89509 ol.layer.Group.prototype,
89510 'setMaxResolution',
89511 ol.layer.Group.prototype.setMaxResolution);
89512
89513goog.exportProperty(
89514 ol.layer.Group.prototype,
89515 'setMinResolution',
89516 ol.layer.Group.prototype.setMinResolution);
89517
89518goog.exportProperty(
89519 ol.layer.Group.prototype,
89520 'setOpacity',
89521 ol.layer.Group.prototype.setOpacity);
89522
89523goog.exportProperty(
89524 ol.layer.Group.prototype,
89525 'setVisible',
89526 ol.layer.Group.prototype.setVisible);
89527
89528goog.exportProperty(
89529 ol.layer.Group.prototype,
89530 'setZIndex',
89531 ol.layer.Group.prototype.setZIndex);
89532
89533goog.exportProperty(
89534 ol.layer.Group.prototype,
89535 'get',
89536 ol.layer.Group.prototype.get);
89537
89538goog.exportProperty(
89539 ol.layer.Group.prototype,
89540 'getKeys',
89541 ol.layer.Group.prototype.getKeys);
89542
89543goog.exportProperty(
89544 ol.layer.Group.prototype,
89545 'getProperties',
89546 ol.layer.Group.prototype.getProperties);
89547
89548goog.exportProperty(
89549 ol.layer.Group.prototype,
89550 'set',
89551 ol.layer.Group.prototype.set);
89552
89553goog.exportProperty(
89554 ol.layer.Group.prototype,
89555 'setProperties',
89556 ol.layer.Group.prototype.setProperties);
89557
89558goog.exportProperty(
89559 ol.layer.Group.prototype,
89560 'unset',
89561 ol.layer.Group.prototype.unset);
89562
89563goog.exportProperty(
89564 ol.layer.Group.prototype,
89565 'changed',
89566 ol.layer.Group.prototype.changed);
89567
89568goog.exportProperty(
89569 ol.layer.Group.prototype,
89570 'dispatchEvent',
89571 ol.layer.Group.prototype.dispatchEvent);
89572
89573goog.exportProperty(
89574 ol.layer.Group.prototype,
89575 'getRevision',
89576 ol.layer.Group.prototype.getRevision);
89577
89578goog.exportProperty(
89579 ol.layer.Group.prototype,
89580 'on',
89581 ol.layer.Group.prototype.on);
89582
89583goog.exportProperty(
89584 ol.layer.Group.prototype,
89585 'once',
89586 ol.layer.Group.prototype.once);
89587
89588goog.exportProperty(
89589 ol.layer.Group.prototype,
89590 'un',
89591 ol.layer.Group.prototype.un);
89592
89593goog.exportProperty(
89594 ol.layer.Layer.prototype,
89595 'getExtent',
89596 ol.layer.Layer.prototype.getExtent);
89597
89598goog.exportProperty(
89599 ol.layer.Layer.prototype,
89600 'getMaxResolution',
89601 ol.layer.Layer.prototype.getMaxResolution);
89602
89603goog.exportProperty(
89604 ol.layer.Layer.prototype,
89605 'getMinResolution',
89606 ol.layer.Layer.prototype.getMinResolution);
89607
89608goog.exportProperty(
89609 ol.layer.Layer.prototype,
89610 'getOpacity',
89611 ol.layer.Layer.prototype.getOpacity);
89612
89613goog.exportProperty(
89614 ol.layer.Layer.prototype,
89615 'getVisible',
89616 ol.layer.Layer.prototype.getVisible);
89617
89618goog.exportProperty(
89619 ol.layer.Layer.prototype,
89620 'getZIndex',
89621 ol.layer.Layer.prototype.getZIndex);
89622
89623goog.exportProperty(
89624 ol.layer.Layer.prototype,
89625 'setExtent',
89626 ol.layer.Layer.prototype.setExtent);
89627
89628goog.exportProperty(
89629 ol.layer.Layer.prototype,
89630 'setMaxResolution',
89631 ol.layer.Layer.prototype.setMaxResolution);
89632
89633goog.exportProperty(
89634 ol.layer.Layer.prototype,
89635 'setMinResolution',
89636 ol.layer.Layer.prototype.setMinResolution);
89637
89638goog.exportProperty(
89639 ol.layer.Layer.prototype,
89640 'setOpacity',
89641 ol.layer.Layer.prototype.setOpacity);
89642
89643goog.exportProperty(
89644 ol.layer.Layer.prototype,
89645 'setVisible',
89646 ol.layer.Layer.prototype.setVisible);
89647
89648goog.exportProperty(
89649 ol.layer.Layer.prototype,
89650 'setZIndex',
89651 ol.layer.Layer.prototype.setZIndex);
89652
89653goog.exportProperty(
89654 ol.layer.Layer.prototype,
89655 'get',
89656 ol.layer.Layer.prototype.get);
89657
89658goog.exportProperty(
89659 ol.layer.Layer.prototype,
89660 'getKeys',
89661 ol.layer.Layer.prototype.getKeys);
89662
89663goog.exportProperty(
89664 ol.layer.Layer.prototype,
89665 'getProperties',
89666 ol.layer.Layer.prototype.getProperties);
89667
89668goog.exportProperty(
89669 ol.layer.Layer.prototype,
89670 'set',
89671 ol.layer.Layer.prototype.set);
89672
89673goog.exportProperty(
89674 ol.layer.Layer.prototype,
89675 'setProperties',
89676 ol.layer.Layer.prototype.setProperties);
89677
89678goog.exportProperty(
89679 ol.layer.Layer.prototype,
89680 'unset',
89681 ol.layer.Layer.prototype.unset);
89682
89683goog.exportProperty(
89684 ol.layer.Layer.prototype,
89685 'changed',
89686 ol.layer.Layer.prototype.changed);
89687
89688goog.exportProperty(
89689 ol.layer.Layer.prototype,
89690 'dispatchEvent',
89691 ol.layer.Layer.prototype.dispatchEvent);
89692
89693goog.exportProperty(
89694 ol.layer.Layer.prototype,
89695 'getRevision',
89696 ol.layer.Layer.prototype.getRevision);
89697
89698goog.exportProperty(
89699 ol.layer.Layer.prototype,
89700 'on',
89701 ol.layer.Layer.prototype.on);
89702
89703goog.exportProperty(
89704 ol.layer.Layer.prototype,
89705 'once',
89706 ol.layer.Layer.prototype.once);
89707
89708goog.exportProperty(
89709 ol.layer.Layer.prototype,
89710 'un',
89711 ol.layer.Layer.prototype.un);
89712
89713goog.exportProperty(
89714 ol.layer.Vector.prototype,
89715 'setMap',
89716 ol.layer.Vector.prototype.setMap);
89717
89718goog.exportProperty(
89719 ol.layer.Vector.prototype,
89720 'setSource',
89721 ol.layer.Vector.prototype.setSource);
89722
89723goog.exportProperty(
89724 ol.layer.Vector.prototype,
89725 'getExtent',
89726 ol.layer.Vector.prototype.getExtent);
89727
89728goog.exportProperty(
89729 ol.layer.Vector.prototype,
89730 'getMaxResolution',
89731 ol.layer.Vector.prototype.getMaxResolution);
89732
89733goog.exportProperty(
89734 ol.layer.Vector.prototype,
89735 'getMinResolution',
89736 ol.layer.Vector.prototype.getMinResolution);
89737
89738goog.exportProperty(
89739 ol.layer.Vector.prototype,
89740 'getOpacity',
89741 ol.layer.Vector.prototype.getOpacity);
89742
89743goog.exportProperty(
89744 ol.layer.Vector.prototype,
89745 'getVisible',
89746 ol.layer.Vector.prototype.getVisible);
89747
89748goog.exportProperty(
89749 ol.layer.Vector.prototype,
89750 'getZIndex',
89751 ol.layer.Vector.prototype.getZIndex);
89752
89753goog.exportProperty(
89754 ol.layer.Vector.prototype,
89755 'setExtent',
89756 ol.layer.Vector.prototype.setExtent);
89757
89758goog.exportProperty(
89759 ol.layer.Vector.prototype,
89760 'setMaxResolution',
89761 ol.layer.Vector.prototype.setMaxResolution);
89762
89763goog.exportProperty(
89764 ol.layer.Vector.prototype,
89765 'setMinResolution',
89766 ol.layer.Vector.prototype.setMinResolution);
89767
89768goog.exportProperty(
89769 ol.layer.Vector.prototype,
89770 'setOpacity',
89771 ol.layer.Vector.prototype.setOpacity);
89772
89773goog.exportProperty(
89774 ol.layer.Vector.prototype,
89775 'setVisible',
89776 ol.layer.Vector.prototype.setVisible);
89777
89778goog.exportProperty(
89779 ol.layer.Vector.prototype,
89780 'setZIndex',
89781 ol.layer.Vector.prototype.setZIndex);
89782
89783goog.exportProperty(
89784 ol.layer.Vector.prototype,
89785 'get',
89786 ol.layer.Vector.prototype.get);
89787
89788goog.exportProperty(
89789 ol.layer.Vector.prototype,
89790 'getKeys',
89791 ol.layer.Vector.prototype.getKeys);
89792
89793goog.exportProperty(
89794 ol.layer.Vector.prototype,
89795 'getProperties',
89796 ol.layer.Vector.prototype.getProperties);
89797
89798goog.exportProperty(
89799 ol.layer.Vector.prototype,
89800 'set',
89801 ol.layer.Vector.prototype.set);
89802
89803goog.exportProperty(
89804 ol.layer.Vector.prototype,
89805 'setProperties',
89806 ol.layer.Vector.prototype.setProperties);
89807
89808goog.exportProperty(
89809 ol.layer.Vector.prototype,
89810 'unset',
89811 ol.layer.Vector.prototype.unset);
89812
89813goog.exportProperty(
89814 ol.layer.Vector.prototype,
89815 'changed',
89816 ol.layer.Vector.prototype.changed);
89817
89818goog.exportProperty(
89819 ol.layer.Vector.prototype,
89820 'dispatchEvent',
89821 ol.layer.Vector.prototype.dispatchEvent);
89822
89823goog.exportProperty(
89824 ol.layer.Vector.prototype,
89825 'getRevision',
89826 ol.layer.Vector.prototype.getRevision);
89827
89828goog.exportProperty(
89829 ol.layer.Vector.prototype,
89830 'on',
89831 ol.layer.Vector.prototype.on);
89832
89833goog.exportProperty(
89834 ol.layer.Vector.prototype,
89835 'once',
89836 ol.layer.Vector.prototype.once);
89837
89838goog.exportProperty(
89839 ol.layer.Vector.prototype,
89840 'un',
89841 ol.layer.Vector.prototype.un);
89842
89843goog.exportProperty(
89844 ol.layer.Heatmap.prototype,
89845 'getSource',
89846 ol.layer.Heatmap.prototype.getSource);
89847
89848goog.exportProperty(
89849 ol.layer.Heatmap.prototype,
89850 'getStyle',
89851 ol.layer.Heatmap.prototype.getStyle);
89852
89853goog.exportProperty(
89854 ol.layer.Heatmap.prototype,
89855 'getStyleFunction',
89856 ol.layer.Heatmap.prototype.getStyleFunction);
89857
89858goog.exportProperty(
89859 ol.layer.Heatmap.prototype,
89860 'setStyle',
89861 ol.layer.Heatmap.prototype.setStyle);
89862
89863goog.exportProperty(
89864 ol.layer.Heatmap.prototype,
89865 'setMap',
89866 ol.layer.Heatmap.prototype.setMap);
89867
89868goog.exportProperty(
89869 ol.layer.Heatmap.prototype,
89870 'setSource',
89871 ol.layer.Heatmap.prototype.setSource);
89872
89873goog.exportProperty(
89874 ol.layer.Heatmap.prototype,
89875 'getExtent',
89876 ol.layer.Heatmap.prototype.getExtent);
89877
89878goog.exportProperty(
89879 ol.layer.Heatmap.prototype,
89880 'getMaxResolution',
89881 ol.layer.Heatmap.prototype.getMaxResolution);
89882
89883goog.exportProperty(
89884 ol.layer.Heatmap.prototype,
89885 'getMinResolution',
89886 ol.layer.Heatmap.prototype.getMinResolution);
89887
89888goog.exportProperty(
89889 ol.layer.Heatmap.prototype,
89890 'getOpacity',
89891 ol.layer.Heatmap.prototype.getOpacity);
89892
89893goog.exportProperty(
89894 ol.layer.Heatmap.prototype,
89895 'getVisible',
89896 ol.layer.Heatmap.prototype.getVisible);
89897
89898goog.exportProperty(
89899 ol.layer.Heatmap.prototype,
89900 'getZIndex',
89901 ol.layer.Heatmap.prototype.getZIndex);
89902
89903goog.exportProperty(
89904 ol.layer.Heatmap.prototype,
89905 'setExtent',
89906 ol.layer.Heatmap.prototype.setExtent);
89907
89908goog.exportProperty(
89909 ol.layer.Heatmap.prototype,
89910 'setMaxResolution',
89911 ol.layer.Heatmap.prototype.setMaxResolution);
89912
89913goog.exportProperty(
89914 ol.layer.Heatmap.prototype,
89915 'setMinResolution',
89916 ol.layer.Heatmap.prototype.setMinResolution);
89917
89918goog.exportProperty(
89919 ol.layer.Heatmap.prototype,
89920 'setOpacity',
89921 ol.layer.Heatmap.prototype.setOpacity);
89922
89923goog.exportProperty(
89924 ol.layer.Heatmap.prototype,
89925 'setVisible',
89926 ol.layer.Heatmap.prototype.setVisible);
89927
89928goog.exportProperty(
89929 ol.layer.Heatmap.prototype,
89930 'setZIndex',
89931 ol.layer.Heatmap.prototype.setZIndex);
89932
89933goog.exportProperty(
89934 ol.layer.Heatmap.prototype,
89935 'get',
89936 ol.layer.Heatmap.prototype.get);
89937
89938goog.exportProperty(
89939 ol.layer.Heatmap.prototype,
89940 'getKeys',
89941 ol.layer.Heatmap.prototype.getKeys);
89942
89943goog.exportProperty(
89944 ol.layer.Heatmap.prototype,
89945 'getProperties',
89946 ol.layer.Heatmap.prototype.getProperties);
89947
89948goog.exportProperty(
89949 ol.layer.Heatmap.prototype,
89950 'set',
89951 ol.layer.Heatmap.prototype.set);
89952
89953goog.exportProperty(
89954 ol.layer.Heatmap.prototype,
89955 'setProperties',
89956 ol.layer.Heatmap.prototype.setProperties);
89957
89958goog.exportProperty(
89959 ol.layer.Heatmap.prototype,
89960 'unset',
89961 ol.layer.Heatmap.prototype.unset);
89962
89963goog.exportProperty(
89964 ol.layer.Heatmap.prototype,
89965 'changed',
89966 ol.layer.Heatmap.prototype.changed);
89967
89968goog.exportProperty(
89969 ol.layer.Heatmap.prototype,
89970 'dispatchEvent',
89971 ol.layer.Heatmap.prototype.dispatchEvent);
89972
89973goog.exportProperty(
89974 ol.layer.Heatmap.prototype,
89975 'getRevision',
89976 ol.layer.Heatmap.prototype.getRevision);
89977
89978goog.exportProperty(
89979 ol.layer.Heatmap.prototype,
89980 'on',
89981 ol.layer.Heatmap.prototype.on);
89982
89983goog.exportProperty(
89984 ol.layer.Heatmap.prototype,
89985 'once',
89986 ol.layer.Heatmap.prototype.once);
89987
89988goog.exportProperty(
89989 ol.layer.Heatmap.prototype,
89990 'un',
89991 ol.layer.Heatmap.prototype.un);
89992
89993goog.exportProperty(
89994 ol.layer.Image.prototype,
89995 'setMap',
89996 ol.layer.Image.prototype.setMap);
89997
89998goog.exportProperty(
89999 ol.layer.Image.prototype,
90000 'setSource',
90001 ol.layer.Image.prototype.setSource);
90002
90003goog.exportProperty(
90004 ol.layer.Image.prototype,
90005 'getExtent',
90006 ol.layer.Image.prototype.getExtent);
90007
90008goog.exportProperty(
90009 ol.layer.Image.prototype,
90010 'getMaxResolution',
90011 ol.layer.Image.prototype.getMaxResolution);
90012
90013goog.exportProperty(
90014 ol.layer.Image.prototype,
90015 'getMinResolution',
90016 ol.layer.Image.prototype.getMinResolution);
90017
90018goog.exportProperty(
90019 ol.layer.Image.prototype,
90020 'getOpacity',
90021 ol.layer.Image.prototype.getOpacity);
90022
90023goog.exportProperty(
90024 ol.layer.Image.prototype,
90025 'getVisible',
90026 ol.layer.Image.prototype.getVisible);
90027
90028goog.exportProperty(
90029 ol.layer.Image.prototype,
90030 'getZIndex',
90031 ol.layer.Image.prototype.getZIndex);
90032
90033goog.exportProperty(
90034 ol.layer.Image.prototype,
90035 'setExtent',
90036 ol.layer.Image.prototype.setExtent);
90037
90038goog.exportProperty(
90039 ol.layer.Image.prototype,
90040 'setMaxResolution',
90041 ol.layer.Image.prototype.setMaxResolution);
90042
90043goog.exportProperty(
90044 ol.layer.Image.prototype,
90045 'setMinResolution',
90046 ol.layer.Image.prototype.setMinResolution);
90047
90048goog.exportProperty(
90049 ol.layer.Image.prototype,
90050 'setOpacity',
90051 ol.layer.Image.prototype.setOpacity);
90052
90053goog.exportProperty(
90054 ol.layer.Image.prototype,
90055 'setVisible',
90056 ol.layer.Image.prototype.setVisible);
90057
90058goog.exportProperty(
90059 ol.layer.Image.prototype,
90060 'setZIndex',
90061 ol.layer.Image.prototype.setZIndex);
90062
90063goog.exportProperty(
90064 ol.layer.Image.prototype,
90065 'get',
90066 ol.layer.Image.prototype.get);
90067
90068goog.exportProperty(
90069 ol.layer.Image.prototype,
90070 'getKeys',
90071 ol.layer.Image.prototype.getKeys);
90072
90073goog.exportProperty(
90074 ol.layer.Image.prototype,
90075 'getProperties',
90076 ol.layer.Image.prototype.getProperties);
90077
90078goog.exportProperty(
90079 ol.layer.Image.prototype,
90080 'set',
90081 ol.layer.Image.prototype.set);
90082
90083goog.exportProperty(
90084 ol.layer.Image.prototype,
90085 'setProperties',
90086 ol.layer.Image.prototype.setProperties);
90087
90088goog.exportProperty(
90089 ol.layer.Image.prototype,
90090 'unset',
90091 ol.layer.Image.prototype.unset);
90092
90093goog.exportProperty(
90094 ol.layer.Image.prototype,
90095 'changed',
90096 ol.layer.Image.prototype.changed);
90097
90098goog.exportProperty(
90099 ol.layer.Image.prototype,
90100 'dispatchEvent',
90101 ol.layer.Image.prototype.dispatchEvent);
90102
90103goog.exportProperty(
90104 ol.layer.Image.prototype,
90105 'getRevision',
90106 ol.layer.Image.prototype.getRevision);
90107
90108goog.exportProperty(
90109 ol.layer.Image.prototype,
90110 'on',
90111 ol.layer.Image.prototype.on);
90112
90113goog.exportProperty(
90114 ol.layer.Image.prototype,
90115 'once',
90116 ol.layer.Image.prototype.once);
90117
90118goog.exportProperty(
90119 ol.layer.Image.prototype,
90120 'un',
90121 ol.layer.Image.prototype.un);
90122
90123goog.exportProperty(
90124 ol.layer.Tile.prototype,
90125 'setMap',
90126 ol.layer.Tile.prototype.setMap);
90127
90128goog.exportProperty(
90129 ol.layer.Tile.prototype,
90130 'setSource',
90131 ol.layer.Tile.prototype.setSource);
90132
90133goog.exportProperty(
90134 ol.layer.Tile.prototype,
90135 'getExtent',
90136 ol.layer.Tile.prototype.getExtent);
90137
90138goog.exportProperty(
90139 ol.layer.Tile.prototype,
90140 'getMaxResolution',
90141 ol.layer.Tile.prototype.getMaxResolution);
90142
90143goog.exportProperty(
90144 ol.layer.Tile.prototype,
90145 'getMinResolution',
90146 ol.layer.Tile.prototype.getMinResolution);
90147
90148goog.exportProperty(
90149 ol.layer.Tile.prototype,
90150 'getOpacity',
90151 ol.layer.Tile.prototype.getOpacity);
90152
90153goog.exportProperty(
90154 ol.layer.Tile.prototype,
90155 'getVisible',
90156 ol.layer.Tile.prototype.getVisible);
90157
90158goog.exportProperty(
90159 ol.layer.Tile.prototype,
90160 'getZIndex',
90161 ol.layer.Tile.prototype.getZIndex);
90162
90163goog.exportProperty(
90164 ol.layer.Tile.prototype,
90165 'setExtent',
90166 ol.layer.Tile.prototype.setExtent);
90167
90168goog.exportProperty(
90169 ol.layer.Tile.prototype,
90170 'setMaxResolution',
90171 ol.layer.Tile.prototype.setMaxResolution);
90172
90173goog.exportProperty(
90174 ol.layer.Tile.prototype,
90175 'setMinResolution',
90176 ol.layer.Tile.prototype.setMinResolution);
90177
90178goog.exportProperty(
90179 ol.layer.Tile.prototype,
90180 'setOpacity',
90181 ol.layer.Tile.prototype.setOpacity);
90182
90183goog.exportProperty(
90184 ol.layer.Tile.prototype,
90185 'setVisible',
90186 ol.layer.Tile.prototype.setVisible);
90187
90188goog.exportProperty(
90189 ol.layer.Tile.prototype,
90190 'setZIndex',
90191 ol.layer.Tile.prototype.setZIndex);
90192
90193goog.exportProperty(
90194 ol.layer.Tile.prototype,
90195 'get',
90196 ol.layer.Tile.prototype.get);
90197
90198goog.exportProperty(
90199 ol.layer.Tile.prototype,
90200 'getKeys',
90201 ol.layer.Tile.prototype.getKeys);
90202
90203goog.exportProperty(
90204 ol.layer.Tile.prototype,
90205 'getProperties',
90206 ol.layer.Tile.prototype.getProperties);
90207
90208goog.exportProperty(
90209 ol.layer.Tile.prototype,
90210 'set',
90211 ol.layer.Tile.prototype.set);
90212
90213goog.exportProperty(
90214 ol.layer.Tile.prototype,
90215 'setProperties',
90216 ol.layer.Tile.prototype.setProperties);
90217
90218goog.exportProperty(
90219 ol.layer.Tile.prototype,
90220 'unset',
90221 ol.layer.Tile.prototype.unset);
90222
90223goog.exportProperty(
90224 ol.layer.Tile.prototype,
90225 'changed',
90226 ol.layer.Tile.prototype.changed);
90227
90228goog.exportProperty(
90229 ol.layer.Tile.prototype,
90230 'dispatchEvent',
90231 ol.layer.Tile.prototype.dispatchEvent);
90232
90233goog.exportProperty(
90234 ol.layer.Tile.prototype,
90235 'getRevision',
90236 ol.layer.Tile.prototype.getRevision);
90237
90238goog.exportProperty(
90239 ol.layer.Tile.prototype,
90240 'on',
90241 ol.layer.Tile.prototype.on);
90242
90243goog.exportProperty(
90244 ol.layer.Tile.prototype,
90245 'once',
90246 ol.layer.Tile.prototype.once);
90247
90248goog.exportProperty(
90249 ol.layer.Tile.prototype,
90250 'un',
90251 ol.layer.Tile.prototype.un);
90252
90253goog.exportProperty(
90254 ol.layer.VectorTile.prototype,
90255 'getStyle',
90256 ol.layer.VectorTile.prototype.getStyle);
90257
90258goog.exportProperty(
90259 ol.layer.VectorTile.prototype,
90260 'getStyleFunction',
90261 ol.layer.VectorTile.prototype.getStyleFunction);
90262
90263goog.exportProperty(
90264 ol.layer.VectorTile.prototype,
90265 'setStyle',
90266 ol.layer.VectorTile.prototype.setStyle);
90267
90268goog.exportProperty(
90269 ol.layer.VectorTile.prototype,
90270 'setMap',
90271 ol.layer.VectorTile.prototype.setMap);
90272
90273goog.exportProperty(
90274 ol.layer.VectorTile.prototype,
90275 'setSource',
90276 ol.layer.VectorTile.prototype.setSource);
90277
90278goog.exportProperty(
90279 ol.layer.VectorTile.prototype,
90280 'getExtent',
90281 ol.layer.VectorTile.prototype.getExtent);
90282
90283goog.exportProperty(
90284 ol.layer.VectorTile.prototype,
90285 'getMaxResolution',
90286 ol.layer.VectorTile.prototype.getMaxResolution);
90287
90288goog.exportProperty(
90289 ol.layer.VectorTile.prototype,
90290 'getMinResolution',
90291 ol.layer.VectorTile.prototype.getMinResolution);
90292
90293goog.exportProperty(
90294 ol.layer.VectorTile.prototype,
90295 'getOpacity',
90296 ol.layer.VectorTile.prototype.getOpacity);
90297
90298goog.exportProperty(
90299 ol.layer.VectorTile.prototype,
90300 'getVisible',
90301 ol.layer.VectorTile.prototype.getVisible);
90302
90303goog.exportProperty(
90304 ol.layer.VectorTile.prototype,
90305 'getZIndex',
90306 ol.layer.VectorTile.prototype.getZIndex);
90307
90308goog.exportProperty(
90309 ol.layer.VectorTile.prototype,
90310 'setExtent',
90311 ol.layer.VectorTile.prototype.setExtent);
90312
90313goog.exportProperty(
90314 ol.layer.VectorTile.prototype,
90315 'setMaxResolution',
90316 ol.layer.VectorTile.prototype.setMaxResolution);
90317
90318goog.exportProperty(
90319 ol.layer.VectorTile.prototype,
90320 'setMinResolution',
90321 ol.layer.VectorTile.prototype.setMinResolution);
90322
90323goog.exportProperty(
90324 ol.layer.VectorTile.prototype,
90325 'setOpacity',
90326 ol.layer.VectorTile.prototype.setOpacity);
90327
90328goog.exportProperty(
90329 ol.layer.VectorTile.prototype,
90330 'setVisible',
90331 ol.layer.VectorTile.prototype.setVisible);
90332
90333goog.exportProperty(
90334 ol.layer.VectorTile.prototype,
90335 'setZIndex',
90336 ol.layer.VectorTile.prototype.setZIndex);
90337
90338goog.exportProperty(
90339 ol.layer.VectorTile.prototype,
90340 'get',
90341 ol.layer.VectorTile.prototype.get);
90342
90343goog.exportProperty(
90344 ol.layer.VectorTile.prototype,
90345 'getKeys',
90346 ol.layer.VectorTile.prototype.getKeys);
90347
90348goog.exportProperty(
90349 ol.layer.VectorTile.prototype,
90350 'getProperties',
90351 ol.layer.VectorTile.prototype.getProperties);
90352
90353goog.exportProperty(
90354 ol.layer.VectorTile.prototype,
90355 'set',
90356 ol.layer.VectorTile.prototype.set);
90357
90358goog.exportProperty(
90359 ol.layer.VectorTile.prototype,
90360 'setProperties',
90361 ol.layer.VectorTile.prototype.setProperties);
90362
90363goog.exportProperty(
90364 ol.layer.VectorTile.prototype,
90365 'unset',
90366 ol.layer.VectorTile.prototype.unset);
90367
90368goog.exportProperty(
90369 ol.layer.VectorTile.prototype,
90370 'changed',
90371 ol.layer.VectorTile.prototype.changed);
90372
90373goog.exportProperty(
90374 ol.layer.VectorTile.prototype,
90375 'dispatchEvent',
90376 ol.layer.VectorTile.prototype.dispatchEvent);
90377
90378goog.exportProperty(
90379 ol.layer.VectorTile.prototype,
90380 'getRevision',
90381 ol.layer.VectorTile.prototype.getRevision);
90382
90383goog.exportProperty(
90384 ol.layer.VectorTile.prototype,
90385 'on',
90386 ol.layer.VectorTile.prototype.on);
90387
90388goog.exportProperty(
90389 ol.layer.VectorTile.prototype,
90390 'once',
90391 ol.layer.VectorTile.prototype.once);
90392
90393goog.exportProperty(
90394 ol.layer.VectorTile.prototype,
90395 'un',
90396 ol.layer.VectorTile.prototype.un);
90397
90398goog.exportProperty(
90399 ol.interaction.Interaction.prototype,
90400 'get',
90401 ol.interaction.Interaction.prototype.get);
90402
90403goog.exportProperty(
90404 ol.interaction.Interaction.prototype,
90405 'getKeys',
90406 ol.interaction.Interaction.prototype.getKeys);
90407
90408goog.exportProperty(
90409 ol.interaction.Interaction.prototype,
90410 'getProperties',
90411 ol.interaction.Interaction.prototype.getProperties);
90412
90413goog.exportProperty(
90414 ol.interaction.Interaction.prototype,
90415 'set',
90416 ol.interaction.Interaction.prototype.set);
90417
90418goog.exportProperty(
90419 ol.interaction.Interaction.prototype,
90420 'setProperties',
90421 ol.interaction.Interaction.prototype.setProperties);
90422
90423goog.exportProperty(
90424 ol.interaction.Interaction.prototype,
90425 'unset',
90426 ol.interaction.Interaction.prototype.unset);
90427
90428goog.exportProperty(
90429 ol.interaction.Interaction.prototype,
90430 'changed',
90431 ol.interaction.Interaction.prototype.changed);
90432
90433goog.exportProperty(
90434 ol.interaction.Interaction.prototype,
90435 'dispatchEvent',
90436 ol.interaction.Interaction.prototype.dispatchEvent);
90437
90438goog.exportProperty(
90439 ol.interaction.Interaction.prototype,
90440 'getRevision',
90441 ol.interaction.Interaction.prototype.getRevision);
90442
90443goog.exportProperty(
90444 ol.interaction.Interaction.prototype,
90445 'on',
90446 ol.interaction.Interaction.prototype.on);
90447
90448goog.exportProperty(
90449 ol.interaction.Interaction.prototype,
90450 'once',
90451 ol.interaction.Interaction.prototype.once);
90452
90453goog.exportProperty(
90454 ol.interaction.Interaction.prototype,
90455 'un',
90456 ol.interaction.Interaction.prototype.un);
90457
90458goog.exportProperty(
90459 ol.interaction.DoubleClickZoom.prototype,
90460 'getActive',
90461 ol.interaction.DoubleClickZoom.prototype.getActive);
90462
90463goog.exportProperty(
90464 ol.interaction.DoubleClickZoom.prototype,
90465 'getMap',
90466 ol.interaction.DoubleClickZoom.prototype.getMap);
90467
90468goog.exportProperty(
90469 ol.interaction.DoubleClickZoom.prototype,
90470 'setActive',
90471 ol.interaction.DoubleClickZoom.prototype.setActive);
90472
90473goog.exportProperty(
90474 ol.interaction.DoubleClickZoom.prototype,
90475 'get',
90476 ol.interaction.DoubleClickZoom.prototype.get);
90477
90478goog.exportProperty(
90479 ol.interaction.DoubleClickZoom.prototype,
90480 'getKeys',
90481 ol.interaction.DoubleClickZoom.prototype.getKeys);
90482
90483goog.exportProperty(
90484 ol.interaction.DoubleClickZoom.prototype,
90485 'getProperties',
90486 ol.interaction.DoubleClickZoom.prototype.getProperties);
90487
90488goog.exportProperty(
90489 ol.interaction.DoubleClickZoom.prototype,
90490 'set',
90491 ol.interaction.DoubleClickZoom.prototype.set);
90492
90493goog.exportProperty(
90494 ol.interaction.DoubleClickZoom.prototype,
90495 'setProperties',
90496 ol.interaction.DoubleClickZoom.prototype.setProperties);
90497
90498goog.exportProperty(
90499 ol.interaction.DoubleClickZoom.prototype,
90500 'unset',
90501 ol.interaction.DoubleClickZoom.prototype.unset);
90502
90503goog.exportProperty(
90504 ol.interaction.DoubleClickZoom.prototype,
90505 'changed',
90506 ol.interaction.DoubleClickZoom.prototype.changed);
90507
90508goog.exportProperty(
90509 ol.interaction.DoubleClickZoom.prototype,
90510 'dispatchEvent',
90511 ol.interaction.DoubleClickZoom.prototype.dispatchEvent);
90512
90513goog.exportProperty(
90514 ol.interaction.DoubleClickZoom.prototype,
90515 'getRevision',
90516 ol.interaction.DoubleClickZoom.prototype.getRevision);
90517
90518goog.exportProperty(
90519 ol.interaction.DoubleClickZoom.prototype,
90520 'on',
90521 ol.interaction.DoubleClickZoom.prototype.on);
90522
90523goog.exportProperty(
90524 ol.interaction.DoubleClickZoom.prototype,
90525 'once',
90526 ol.interaction.DoubleClickZoom.prototype.once);
90527
90528goog.exportProperty(
90529 ol.interaction.DoubleClickZoom.prototype,
90530 'un',
90531 ol.interaction.DoubleClickZoom.prototype.un);
90532
90533goog.exportProperty(
90534 ol.interaction.DragAndDrop.prototype,
90535 'getActive',
90536 ol.interaction.DragAndDrop.prototype.getActive);
90537
90538goog.exportProperty(
90539 ol.interaction.DragAndDrop.prototype,
90540 'getMap',
90541 ol.interaction.DragAndDrop.prototype.getMap);
90542
90543goog.exportProperty(
90544 ol.interaction.DragAndDrop.prototype,
90545 'setActive',
90546 ol.interaction.DragAndDrop.prototype.setActive);
90547
90548goog.exportProperty(
90549 ol.interaction.DragAndDrop.prototype,
90550 'get',
90551 ol.interaction.DragAndDrop.prototype.get);
90552
90553goog.exportProperty(
90554 ol.interaction.DragAndDrop.prototype,
90555 'getKeys',
90556 ol.interaction.DragAndDrop.prototype.getKeys);
90557
90558goog.exportProperty(
90559 ol.interaction.DragAndDrop.prototype,
90560 'getProperties',
90561 ol.interaction.DragAndDrop.prototype.getProperties);
90562
90563goog.exportProperty(
90564 ol.interaction.DragAndDrop.prototype,
90565 'set',
90566 ol.interaction.DragAndDrop.prototype.set);
90567
90568goog.exportProperty(
90569 ol.interaction.DragAndDrop.prototype,
90570 'setProperties',
90571 ol.interaction.DragAndDrop.prototype.setProperties);
90572
90573goog.exportProperty(
90574 ol.interaction.DragAndDrop.prototype,
90575 'unset',
90576 ol.interaction.DragAndDrop.prototype.unset);
90577
90578goog.exportProperty(
90579 ol.interaction.DragAndDrop.prototype,
90580 'changed',
90581 ol.interaction.DragAndDrop.prototype.changed);
90582
90583goog.exportProperty(
90584 ol.interaction.DragAndDrop.prototype,
90585 'dispatchEvent',
90586 ol.interaction.DragAndDrop.prototype.dispatchEvent);
90587
90588goog.exportProperty(
90589 ol.interaction.DragAndDrop.prototype,
90590 'getRevision',
90591 ol.interaction.DragAndDrop.prototype.getRevision);
90592
90593goog.exportProperty(
90594 ol.interaction.DragAndDrop.prototype,
90595 'on',
90596 ol.interaction.DragAndDrop.prototype.on);
90597
90598goog.exportProperty(
90599 ol.interaction.DragAndDrop.prototype,
90600 'once',
90601 ol.interaction.DragAndDrop.prototype.once);
90602
90603goog.exportProperty(
90604 ol.interaction.DragAndDrop.prototype,
90605 'un',
90606 ol.interaction.DragAndDrop.prototype.un);
90607
90608goog.exportProperty(
90609 ol.interaction.DragAndDrop.Event.prototype,
90610 'type',
90611 ol.interaction.DragAndDrop.Event.prototype.type);
90612
90613goog.exportProperty(
90614 ol.interaction.DragAndDrop.Event.prototype,
90615 'target',
90616 ol.interaction.DragAndDrop.Event.prototype.target);
90617
90618goog.exportProperty(
90619 ol.interaction.DragAndDrop.Event.prototype,
90620 'preventDefault',
90621 ol.interaction.DragAndDrop.Event.prototype.preventDefault);
90622
90623goog.exportProperty(
90624 ol.interaction.DragAndDrop.Event.prototype,
90625 'stopPropagation',
90626 ol.interaction.DragAndDrop.Event.prototype.stopPropagation);
90627
90628goog.exportProperty(
90629 ol.interaction.Pointer.prototype,
90630 'getActive',
90631 ol.interaction.Pointer.prototype.getActive);
90632
90633goog.exportProperty(
90634 ol.interaction.Pointer.prototype,
90635 'getMap',
90636 ol.interaction.Pointer.prototype.getMap);
90637
90638goog.exportProperty(
90639 ol.interaction.Pointer.prototype,
90640 'setActive',
90641 ol.interaction.Pointer.prototype.setActive);
90642
90643goog.exportProperty(
90644 ol.interaction.Pointer.prototype,
90645 'get',
90646 ol.interaction.Pointer.prototype.get);
90647
90648goog.exportProperty(
90649 ol.interaction.Pointer.prototype,
90650 'getKeys',
90651 ol.interaction.Pointer.prototype.getKeys);
90652
90653goog.exportProperty(
90654 ol.interaction.Pointer.prototype,
90655 'getProperties',
90656 ol.interaction.Pointer.prototype.getProperties);
90657
90658goog.exportProperty(
90659 ol.interaction.Pointer.prototype,
90660 'set',
90661 ol.interaction.Pointer.prototype.set);
90662
90663goog.exportProperty(
90664 ol.interaction.Pointer.prototype,
90665 'setProperties',
90666 ol.interaction.Pointer.prototype.setProperties);
90667
90668goog.exportProperty(
90669 ol.interaction.Pointer.prototype,
90670 'unset',
90671 ol.interaction.Pointer.prototype.unset);
90672
90673goog.exportProperty(
90674 ol.interaction.Pointer.prototype,
90675 'changed',
90676 ol.interaction.Pointer.prototype.changed);
90677
90678goog.exportProperty(
90679 ol.interaction.Pointer.prototype,
90680 'dispatchEvent',
90681 ol.interaction.Pointer.prototype.dispatchEvent);
90682
90683goog.exportProperty(
90684 ol.interaction.Pointer.prototype,
90685 'getRevision',
90686 ol.interaction.Pointer.prototype.getRevision);
90687
90688goog.exportProperty(
90689 ol.interaction.Pointer.prototype,
90690 'on',
90691 ol.interaction.Pointer.prototype.on);
90692
90693goog.exportProperty(
90694 ol.interaction.Pointer.prototype,
90695 'once',
90696 ol.interaction.Pointer.prototype.once);
90697
90698goog.exportProperty(
90699 ol.interaction.Pointer.prototype,
90700 'un',
90701 ol.interaction.Pointer.prototype.un);
90702
90703goog.exportProperty(
90704 ol.interaction.DragBox.prototype,
90705 'getActive',
90706 ol.interaction.DragBox.prototype.getActive);
90707
90708goog.exportProperty(
90709 ol.interaction.DragBox.prototype,
90710 'getMap',
90711 ol.interaction.DragBox.prototype.getMap);
90712
90713goog.exportProperty(
90714 ol.interaction.DragBox.prototype,
90715 'setActive',
90716 ol.interaction.DragBox.prototype.setActive);
90717
90718goog.exportProperty(
90719 ol.interaction.DragBox.prototype,
90720 'get',
90721 ol.interaction.DragBox.prototype.get);
90722
90723goog.exportProperty(
90724 ol.interaction.DragBox.prototype,
90725 'getKeys',
90726 ol.interaction.DragBox.prototype.getKeys);
90727
90728goog.exportProperty(
90729 ol.interaction.DragBox.prototype,
90730 'getProperties',
90731 ol.interaction.DragBox.prototype.getProperties);
90732
90733goog.exportProperty(
90734 ol.interaction.DragBox.prototype,
90735 'set',
90736 ol.interaction.DragBox.prototype.set);
90737
90738goog.exportProperty(
90739 ol.interaction.DragBox.prototype,
90740 'setProperties',
90741 ol.interaction.DragBox.prototype.setProperties);
90742
90743goog.exportProperty(
90744 ol.interaction.DragBox.prototype,
90745 'unset',
90746 ol.interaction.DragBox.prototype.unset);
90747
90748goog.exportProperty(
90749 ol.interaction.DragBox.prototype,
90750 'changed',
90751 ol.interaction.DragBox.prototype.changed);
90752
90753goog.exportProperty(
90754 ol.interaction.DragBox.prototype,
90755 'dispatchEvent',
90756 ol.interaction.DragBox.prototype.dispatchEvent);
90757
90758goog.exportProperty(
90759 ol.interaction.DragBox.prototype,
90760 'getRevision',
90761 ol.interaction.DragBox.prototype.getRevision);
90762
90763goog.exportProperty(
90764 ol.interaction.DragBox.prototype,
90765 'on',
90766 ol.interaction.DragBox.prototype.on);
90767
90768goog.exportProperty(
90769 ol.interaction.DragBox.prototype,
90770 'once',
90771 ol.interaction.DragBox.prototype.once);
90772
90773goog.exportProperty(
90774 ol.interaction.DragBox.prototype,
90775 'un',
90776 ol.interaction.DragBox.prototype.un);
90777
90778goog.exportProperty(
90779 ol.interaction.DragBox.Event.prototype,
90780 'type',
90781 ol.interaction.DragBox.Event.prototype.type);
90782
90783goog.exportProperty(
90784 ol.interaction.DragBox.Event.prototype,
90785 'target',
90786 ol.interaction.DragBox.Event.prototype.target);
90787
90788goog.exportProperty(
90789 ol.interaction.DragBox.Event.prototype,
90790 'preventDefault',
90791 ol.interaction.DragBox.Event.prototype.preventDefault);
90792
90793goog.exportProperty(
90794 ol.interaction.DragBox.Event.prototype,
90795 'stopPropagation',
90796 ol.interaction.DragBox.Event.prototype.stopPropagation);
90797
90798goog.exportProperty(
90799 ol.interaction.DragPan.prototype,
90800 'getActive',
90801 ol.interaction.DragPan.prototype.getActive);
90802
90803goog.exportProperty(
90804 ol.interaction.DragPan.prototype,
90805 'getMap',
90806 ol.interaction.DragPan.prototype.getMap);
90807
90808goog.exportProperty(
90809 ol.interaction.DragPan.prototype,
90810 'setActive',
90811 ol.interaction.DragPan.prototype.setActive);
90812
90813goog.exportProperty(
90814 ol.interaction.DragPan.prototype,
90815 'get',
90816 ol.interaction.DragPan.prototype.get);
90817
90818goog.exportProperty(
90819 ol.interaction.DragPan.prototype,
90820 'getKeys',
90821 ol.interaction.DragPan.prototype.getKeys);
90822
90823goog.exportProperty(
90824 ol.interaction.DragPan.prototype,
90825 'getProperties',
90826 ol.interaction.DragPan.prototype.getProperties);
90827
90828goog.exportProperty(
90829 ol.interaction.DragPan.prototype,
90830 'set',
90831 ol.interaction.DragPan.prototype.set);
90832
90833goog.exportProperty(
90834 ol.interaction.DragPan.prototype,
90835 'setProperties',
90836 ol.interaction.DragPan.prototype.setProperties);
90837
90838goog.exportProperty(
90839 ol.interaction.DragPan.prototype,
90840 'unset',
90841 ol.interaction.DragPan.prototype.unset);
90842
90843goog.exportProperty(
90844 ol.interaction.DragPan.prototype,
90845 'changed',
90846 ol.interaction.DragPan.prototype.changed);
90847
90848goog.exportProperty(
90849 ol.interaction.DragPan.prototype,
90850 'dispatchEvent',
90851 ol.interaction.DragPan.prototype.dispatchEvent);
90852
90853goog.exportProperty(
90854 ol.interaction.DragPan.prototype,
90855 'getRevision',
90856 ol.interaction.DragPan.prototype.getRevision);
90857
90858goog.exportProperty(
90859 ol.interaction.DragPan.prototype,
90860 'on',
90861 ol.interaction.DragPan.prototype.on);
90862
90863goog.exportProperty(
90864 ol.interaction.DragPan.prototype,
90865 'once',
90866 ol.interaction.DragPan.prototype.once);
90867
90868goog.exportProperty(
90869 ol.interaction.DragPan.prototype,
90870 'un',
90871 ol.interaction.DragPan.prototype.un);
90872
90873goog.exportProperty(
90874 ol.interaction.DragRotate.prototype,
90875 'getActive',
90876 ol.interaction.DragRotate.prototype.getActive);
90877
90878goog.exportProperty(
90879 ol.interaction.DragRotate.prototype,
90880 'getMap',
90881 ol.interaction.DragRotate.prototype.getMap);
90882
90883goog.exportProperty(
90884 ol.interaction.DragRotate.prototype,
90885 'setActive',
90886 ol.interaction.DragRotate.prototype.setActive);
90887
90888goog.exportProperty(
90889 ol.interaction.DragRotate.prototype,
90890 'get',
90891 ol.interaction.DragRotate.prototype.get);
90892
90893goog.exportProperty(
90894 ol.interaction.DragRotate.prototype,
90895 'getKeys',
90896 ol.interaction.DragRotate.prototype.getKeys);
90897
90898goog.exportProperty(
90899 ol.interaction.DragRotate.prototype,
90900 'getProperties',
90901 ol.interaction.DragRotate.prototype.getProperties);
90902
90903goog.exportProperty(
90904 ol.interaction.DragRotate.prototype,
90905 'set',
90906 ol.interaction.DragRotate.prototype.set);
90907
90908goog.exportProperty(
90909 ol.interaction.DragRotate.prototype,
90910 'setProperties',
90911 ol.interaction.DragRotate.prototype.setProperties);
90912
90913goog.exportProperty(
90914 ol.interaction.DragRotate.prototype,
90915 'unset',
90916 ol.interaction.DragRotate.prototype.unset);
90917
90918goog.exportProperty(
90919 ol.interaction.DragRotate.prototype,
90920 'changed',
90921 ol.interaction.DragRotate.prototype.changed);
90922
90923goog.exportProperty(
90924 ol.interaction.DragRotate.prototype,
90925 'dispatchEvent',
90926 ol.interaction.DragRotate.prototype.dispatchEvent);
90927
90928goog.exportProperty(
90929 ol.interaction.DragRotate.prototype,
90930 'getRevision',
90931 ol.interaction.DragRotate.prototype.getRevision);
90932
90933goog.exportProperty(
90934 ol.interaction.DragRotate.prototype,
90935 'on',
90936 ol.interaction.DragRotate.prototype.on);
90937
90938goog.exportProperty(
90939 ol.interaction.DragRotate.prototype,
90940 'once',
90941 ol.interaction.DragRotate.prototype.once);
90942
90943goog.exportProperty(
90944 ol.interaction.DragRotate.prototype,
90945 'un',
90946 ol.interaction.DragRotate.prototype.un);
90947
90948goog.exportProperty(
90949 ol.interaction.DragRotateAndZoom.prototype,
90950 'getActive',
90951 ol.interaction.DragRotateAndZoom.prototype.getActive);
90952
90953goog.exportProperty(
90954 ol.interaction.DragRotateAndZoom.prototype,
90955 'getMap',
90956 ol.interaction.DragRotateAndZoom.prototype.getMap);
90957
90958goog.exportProperty(
90959 ol.interaction.DragRotateAndZoom.prototype,
90960 'setActive',
90961 ol.interaction.DragRotateAndZoom.prototype.setActive);
90962
90963goog.exportProperty(
90964 ol.interaction.DragRotateAndZoom.prototype,
90965 'get',
90966 ol.interaction.DragRotateAndZoom.prototype.get);
90967
90968goog.exportProperty(
90969 ol.interaction.DragRotateAndZoom.prototype,
90970 'getKeys',
90971 ol.interaction.DragRotateAndZoom.prototype.getKeys);
90972
90973goog.exportProperty(
90974 ol.interaction.DragRotateAndZoom.prototype,
90975 'getProperties',
90976 ol.interaction.DragRotateAndZoom.prototype.getProperties);
90977
90978goog.exportProperty(
90979 ol.interaction.DragRotateAndZoom.prototype,
90980 'set',
90981 ol.interaction.DragRotateAndZoom.prototype.set);
90982
90983goog.exportProperty(
90984 ol.interaction.DragRotateAndZoom.prototype,
90985 'setProperties',
90986 ol.interaction.DragRotateAndZoom.prototype.setProperties);
90987
90988goog.exportProperty(
90989 ol.interaction.DragRotateAndZoom.prototype,
90990 'unset',
90991 ol.interaction.DragRotateAndZoom.prototype.unset);
90992
90993goog.exportProperty(
90994 ol.interaction.DragRotateAndZoom.prototype,
90995 'changed',
90996 ol.interaction.DragRotateAndZoom.prototype.changed);
90997
90998goog.exportProperty(
90999 ol.interaction.DragRotateAndZoom.prototype,
91000 'dispatchEvent',
91001 ol.interaction.DragRotateAndZoom.prototype.dispatchEvent);
91002
91003goog.exportProperty(
91004 ol.interaction.DragRotateAndZoom.prototype,
91005 'getRevision',
91006 ol.interaction.DragRotateAndZoom.prototype.getRevision);
91007
91008goog.exportProperty(
91009 ol.interaction.DragRotateAndZoom.prototype,
91010 'on',
91011 ol.interaction.DragRotateAndZoom.prototype.on);
91012
91013goog.exportProperty(
91014 ol.interaction.DragRotateAndZoom.prototype,
91015 'once',
91016 ol.interaction.DragRotateAndZoom.prototype.once);
91017
91018goog.exportProperty(
91019 ol.interaction.DragRotateAndZoom.prototype,
91020 'un',
91021 ol.interaction.DragRotateAndZoom.prototype.un);
91022
91023goog.exportProperty(
91024 ol.interaction.DragZoom.prototype,
91025 'getGeometry',
91026 ol.interaction.DragZoom.prototype.getGeometry);
91027
91028goog.exportProperty(
91029 ol.interaction.DragZoom.prototype,
91030 'getActive',
91031 ol.interaction.DragZoom.prototype.getActive);
91032
91033goog.exportProperty(
91034 ol.interaction.DragZoom.prototype,
91035 'getMap',
91036 ol.interaction.DragZoom.prototype.getMap);
91037
91038goog.exportProperty(
91039 ol.interaction.DragZoom.prototype,
91040 'setActive',
91041 ol.interaction.DragZoom.prototype.setActive);
91042
91043goog.exportProperty(
91044 ol.interaction.DragZoom.prototype,
91045 'get',
91046 ol.interaction.DragZoom.prototype.get);
91047
91048goog.exportProperty(
91049 ol.interaction.DragZoom.prototype,
91050 'getKeys',
91051 ol.interaction.DragZoom.prototype.getKeys);
91052
91053goog.exportProperty(
91054 ol.interaction.DragZoom.prototype,
91055 'getProperties',
91056 ol.interaction.DragZoom.prototype.getProperties);
91057
91058goog.exportProperty(
91059 ol.interaction.DragZoom.prototype,
91060 'set',
91061 ol.interaction.DragZoom.prototype.set);
91062
91063goog.exportProperty(
91064 ol.interaction.DragZoom.prototype,
91065 'setProperties',
91066 ol.interaction.DragZoom.prototype.setProperties);
91067
91068goog.exportProperty(
91069 ol.interaction.DragZoom.prototype,
91070 'unset',
91071 ol.interaction.DragZoom.prototype.unset);
91072
91073goog.exportProperty(
91074 ol.interaction.DragZoom.prototype,
91075 'changed',
91076 ol.interaction.DragZoom.prototype.changed);
91077
91078goog.exportProperty(
91079 ol.interaction.DragZoom.prototype,
91080 'dispatchEvent',
91081 ol.interaction.DragZoom.prototype.dispatchEvent);
91082
91083goog.exportProperty(
91084 ol.interaction.DragZoom.prototype,
91085 'getRevision',
91086 ol.interaction.DragZoom.prototype.getRevision);
91087
91088goog.exportProperty(
91089 ol.interaction.DragZoom.prototype,
91090 'on',
91091 ol.interaction.DragZoom.prototype.on);
91092
91093goog.exportProperty(
91094 ol.interaction.DragZoom.prototype,
91095 'once',
91096 ol.interaction.DragZoom.prototype.once);
91097
91098goog.exportProperty(
91099 ol.interaction.DragZoom.prototype,
91100 'un',
91101 ol.interaction.DragZoom.prototype.un);
91102
91103goog.exportProperty(
91104 ol.interaction.Draw.prototype,
91105 'getActive',
91106 ol.interaction.Draw.prototype.getActive);
91107
91108goog.exportProperty(
91109 ol.interaction.Draw.prototype,
91110 'getMap',
91111 ol.interaction.Draw.prototype.getMap);
91112
91113goog.exportProperty(
91114 ol.interaction.Draw.prototype,
91115 'setActive',
91116 ol.interaction.Draw.prototype.setActive);
91117
91118goog.exportProperty(
91119 ol.interaction.Draw.prototype,
91120 'get',
91121 ol.interaction.Draw.prototype.get);
91122
91123goog.exportProperty(
91124 ol.interaction.Draw.prototype,
91125 'getKeys',
91126 ol.interaction.Draw.prototype.getKeys);
91127
91128goog.exportProperty(
91129 ol.interaction.Draw.prototype,
91130 'getProperties',
91131 ol.interaction.Draw.prototype.getProperties);
91132
91133goog.exportProperty(
91134 ol.interaction.Draw.prototype,
91135 'set',
91136 ol.interaction.Draw.prototype.set);
91137
91138goog.exportProperty(
91139 ol.interaction.Draw.prototype,
91140 'setProperties',
91141 ol.interaction.Draw.prototype.setProperties);
91142
91143goog.exportProperty(
91144 ol.interaction.Draw.prototype,
91145 'unset',
91146 ol.interaction.Draw.prototype.unset);
91147
91148goog.exportProperty(
91149 ol.interaction.Draw.prototype,
91150 'changed',
91151 ol.interaction.Draw.prototype.changed);
91152
91153goog.exportProperty(
91154 ol.interaction.Draw.prototype,
91155 'dispatchEvent',
91156 ol.interaction.Draw.prototype.dispatchEvent);
91157
91158goog.exportProperty(
91159 ol.interaction.Draw.prototype,
91160 'getRevision',
91161 ol.interaction.Draw.prototype.getRevision);
91162
91163goog.exportProperty(
91164 ol.interaction.Draw.prototype,
91165 'on',
91166 ol.interaction.Draw.prototype.on);
91167
91168goog.exportProperty(
91169 ol.interaction.Draw.prototype,
91170 'once',
91171 ol.interaction.Draw.prototype.once);
91172
91173goog.exportProperty(
91174 ol.interaction.Draw.prototype,
91175 'un',
91176 ol.interaction.Draw.prototype.un);
91177
91178goog.exportProperty(
91179 ol.interaction.Draw.Event.prototype,
91180 'type',
91181 ol.interaction.Draw.Event.prototype.type);
91182
91183goog.exportProperty(
91184 ol.interaction.Draw.Event.prototype,
91185 'target',
91186 ol.interaction.Draw.Event.prototype.target);
91187
91188goog.exportProperty(
91189 ol.interaction.Draw.Event.prototype,
91190 'preventDefault',
91191 ol.interaction.Draw.Event.prototype.preventDefault);
91192
91193goog.exportProperty(
91194 ol.interaction.Draw.Event.prototype,
91195 'stopPropagation',
91196 ol.interaction.Draw.Event.prototype.stopPropagation);
91197
91198goog.exportProperty(
91199 ol.interaction.Extent.prototype,
91200 'getActive',
91201 ol.interaction.Extent.prototype.getActive);
91202
91203goog.exportProperty(
91204 ol.interaction.Extent.prototype,
91205 'getMap',
91206 ol.interaction.Extent.prototype.getMap);
91207
91208goog.exportProperty(
91209 ol.interaction.Extent.prototype,
91210 'setActive',
91211 ol.interaction.Extent.prototype.setActive);
91212
91213goog.exportProperty(
91214 ol.interaction.Extent.prototype,
91215 'get',
91216 ol.interaction.Extent.prototype.get);
91217
91218goog.exportProperty(
91219 ol.interaction.Extent.prototype,
91220 'getKeys',
91221 ol.interaction.Extent.prototype.getKeys);
91222
91223goog.exportProperty(
91224 ol.interaction.Extent.prototype,
91225 'getProperties',
91226 ol.interaction.Extent.prototype.getProperties);
91227
91228goog.exportProperty(
91229 ol.interaction.Extent.prototype,
91230 'set',
91231 ol.interaction.Extent.prototype.set);
91232
91233goog.exportProperty(
91234 ol.interaction.Extent.prototype,
91235 'setProperties',
91236 ol.interaction.Extent.prototype.setProperties);
91237
91238goog.exportProperty(
91239 ol.interaction.Extent.prototype,
91240 'unset',
91241 ol.interaction.Extent.prototype.unset);
91242
91243goog.exportProperty(
91244 ol.interaction.Extent.prototype,
91245 'changed',
91246 ol.interaction.Extent.prototype.changed);
91247
91248goog.exportProperty(
91249 ol.interaction.Extent.prototype,
91250 'dispatchEvent',
91251 ol.interaction.Extent.prototype.dispatchEvent);
91252
91253goog.exportProperty(
91254 ol.interaction.Extent.prototype,
91255 'getRevision',
91256 ol.interaction.Extent.prototype.getRevision);
91257
91258goog.exportProperty(
91259 ol.interaction.Extent.prototype,
91260 'on',
91261 ol.interaction.Extent.prototype.on);
91262
91263goog.exportProperty(
91264 ol.interaction.Extent.prototype,
91265 'once',
91266 ol.interaction.Extent.prototype.once);
91267
91268goog.exportProperty(
91269 ol.interaction.Extent.prototype,
91270 'un',
91271 ol.interaction.Extent.prototype.un);
91272
91273goog.exportProperty(
91274 ol.interaction.Extent.Event.prototype,
91275 'type',
91276 ol.interaction.Extent.Event.prototype.type);
91277
91278goog.exportProperty(
91279 ol.interaction.Extent.Event.prototype,
91280 'target',
91281 ol.interaction.Extent.Event.prototype.target);
91282
91283goog.exportProperty(
91284 ol.interaction.Extent.Event.prototype,
91285 'preventDefault',
91286 ol.interaction.Extent.Event.prototype.preventDefault);
91287
91288goog.exportProperty(
91289 ol.interaction.Extent.Event.prototype,
91290 'stopPropagation',
91291 ol.interaction.Extent.Event.prototype.stopPropagation);
91292
91293goog.exportProperty(
91294 ol.interaction.KeyboardPan.prototype,
91295 'getActive',
91296 ol.interaction.KeyboardPan.prototype.getActive);
91297
91298goog.exportProperty(
91299 ol.interaction.KeyboardPan.prototype,
91300 'getMap',
91301 ol.interaction.KeyboardPan.prototype.getMap);
91302
91303goog.exportProperty(
91304 ol.interaction.KeyboardPan.prototype,
91305 'setActive',
91306 ol.interaction.KeyboardPan.prototype.setActive);
91307
91308goog.exportProperty(
91309 ol.interaction.KeyboardPan.prototype,
91310 'get',
91311 ol.interaction.KeyboardPan.prototype.get);
91312
91313goog.exportProperty(
91314 ol.interaction.KeyboardPan.prototype,
91315 'getKeys',
91316 ol.interaction.KeyboardPan.prototype.getKeys);
91317
91318goog.exportProperty(
91319 ol.interaction.KeyboardPan.prototype,
91320 'getProperties',
91321 ol.interaction.KeyboardPan.prototype.getProperties);
91322
91323goog.exportProperty(
91324 ol.interaction.KeyboardPan.prototype,
91325 'set',
91326 ol.interaction.KeyboardPan.prototype.set);
91327
91328goog.exportProperty(
91329 ol.interaction.KeyboardPan.prototype,
91330 'setProperties',
91331 ol.interaction.KeyboardPan.prototype.setProperties);
91332
91333goog.exportProperty(
91334 ol.interaction.KeyboardPan.prototype,
91335 'unset',
91336 ol.interaction.KeyboardPan.prototype.unset);
91337
91338goog.exportProperty(
91339 ol.interaction.KeyboardPan.prototype,
91340 'changed',
91341 ol.interaction.KeyboardPan.prototype.changed);
91342
91343goog.exportProperty(
91344 ol.interaction.KeyboardPan.prototype,
91345 'dispatchEvent',
91346 ol.interaction.KeyboardPan.prototype.dispatchEvent);
91347
91348goog.exportProperty(
91349 ol.interaction.KeyboardPan.prototype,
91350 'getRevision',
91351 ol.interaction.KeyboardPan.prototype.getRevision);
91352
91353goog.exportProperty(
91354 ol.interaction.KeyboardPan.prototype,
91355 'on',
91356 ol.interaction.KeyboardPan.prototype.on);
91357
91358goog.exportProperty(
91359 ol.interaction.KeyboardPan.prototype,
91360 'once',
91361 ol.interaction.KeyboardPan.prototype.once);
91362
91363goog.exportProperty(
91364 ol.interaction.KeyboardPan.prototype,
91365 'un',
91366 ol.interaction.KeyboardPan.prototype.un);
91367
91368goog.exportProperty(
91369 ol.interaction.KeyboardZoom.prototype,
91370 'getActive',
91371 ol.interaction.KeyboardZoom.prototype.getActive);
91372
91373goog.exportProperty(
91374 ol.interaction.KeyboardZoom.prototype,
91375 'getMap',
91376 ol.interaction.KeyboardZoom.prototype.getMap);
91377
91378goog.exportProperty(
91379 ol.interaction.KeyboardZoom.prototype,
91380 'setActive',
91381 ol.interaction.KeyboardZoom.prototype.setActive);
91382
91383goog.exportProperty(
91384 ol.interaction.KeyboardZoom.prototype,
91385 'get',
91386 ol.interaction.KeyboardZoom.prototype.get);
91387
91388goog.exportProperty(
91389 ol.interaction.KeyboardZoom.prototype,
91390 'getKeys',
91391 ol.interaction.KeyboardZoom.prototype.getKeys);
91392
91393goog.exportProperty(
91394 ol.interaction.KeyboardZoom.prototype,
91395 'getProperties',
91396 ol.interaction.KeyboardZoom.prototype.getProperties);
91397
91398goog.exportProperty(
91399 ol.interaction.KeyboardZoom.prototype,
91400 'set',
91401 ol.interaction.KeyboardZoom.prototype.set);
91402
91403goog.exportProperty(
91404 ol.interaction.KeyboardZoom.prototype,
91405 'setProperties',
91406 ol.interaction.KeyboardZoom.prototype.setProperties);
91407
91408goog.exportProperty(
91409 ol.interaction.KeyboardZoom.prototype,
91410 'unset',
91411 ol.interaction.KeyboardZoom.prototype.unset);
91412
91413goog.exportProperty(
91414 ol.interaction.KeyboardZoom.prototype,
91415 'changed',
91416 ol.interaction.KeyboardZoom.prototype.changed);
91417
91418goog.exportProperty(
91419 ol.interaction.KeyboardZoom.prototype,
91420 'dispatchEvent',
91421 ol.interaction.KeyboardZoom.prototype.dispatchEvent);
91422
91423goog.exportProperty(
91424 ol.interaction.KeyboardZoom.prototype,
91425 'getRevision',
91426 ol.interaction.KeyboardZoom.prototype.getRevision);
91427
91428goog.exportProperty(
91429 ol.interaction.KeyboardZoom.prototype,
91430 'on',
91431 ol.interaction.KeyboardZoom.prototype.on);
91432
91433goog.exportProperty(
91434 ol.interaction.KeyboardZoom.prototype,
91435 'once',
91436 ol.interaction.KeyboardZoom.prototype.once);
91437
91438goog.exportProperty(
91439 ol.interaction.KeyboardZoom.prototype,
91440 'un',
91441 ol.interaction.KeyboardZoom.prototype.un);
91442
91443goog.exportProperty(
91444 ol.interaction.Modify.prototype,
91445 'getActive',
91446 ol.interaction.Modify.prototype.getActive);
91447
91448goog.exportProperty(
91449 ol.interaction.Modify.prototype,
91450 'getMap',
91451 ol.interaction.Modify.prototype.getMap);
91452
91453goog.exportProperty(
91454 ol.interaction.Modify.prototype,
91455 'setActive',
91456 ol.interaction.Modify.prototype.setActive);
91457
91458goog.exportProperty(
91459 ol.interaction.Modify.prototype,
91460 'get',
91461 ol.interaction.Modify.prototype.get);
91462
91463goog.exportProperty(
91464 ol.interaction.Modify.prototype,
91465 'getKeys',
91466 ol.interaction.Modify.prototype.getKeys);
91467
91468goog.exportProperty(
91469 ol.interaction.Modify.prototype,
91470 'getProperties',
91471 ol.interaction.Modify.prototype.getProperties);
91472
91473goog.exportProperty(
91474 ol.interaction.Modify.prototype,
91475 'set',
91476 ol.interaction.Modify.prototype.set);
91477
91478goog.exportProperty(
91479 ol.interaction.Modify.prototype,
91480 'setProperties',
91481 ol.interaction.Modify.prototype.setProperties);
91482
91483goog.exportProperty(
91484 ol.interaction.Modify.prototype,
91485 'unset',
91486 ol.interaction.Modify.prototype.unset);
91487
91488goog.exportProperty(
91489 ol.interaction.Modify.prototype,
91490 'changed',
91491 ol.interaction.Modify.prototype.changed);
91492
91493goog.exportProperty(
91494 ol.interaction.Modify.prototype,
91495 'dispatchEvent',
91496 ol.interaction.Modify.prototype.dispatchEvent);
91497
91498goog.exportProperty(
91499 ol.interaction.Modify.prototype,
91500 'getRevision',
91501 ol.interaction.Modify.prototype.getRevision);
91502
91503goog.exportProperty(
91504 ol.interaction.Modify.prototype,
91505 'on',
91506 ol.interaction.Modify.prototype.on);
91507
91508goog.exportProperty(
91509 ol.interaction.Modify.prototype,
91510 'once',
91511 ol.interaction.Modify.prototype.once);
91512
91513goog.exportProperty(
91514 ol.interaction.Modify.prototype,
91515 'un',
91516 ol.interaction.Modify.prototype.un);
91517
91518goog.exportProperty(
91519 ol.interaction.Modify.Event.prototype,
91520 'type',
91521 ol.interaction.Modify.Event.prototype.type);
91522
91523goog.exportProperty(
91524 ol.interaction.Modify.Event.prototype,
91525 'target',
91526 ol.interaction.Modify.Event.prototype.target);
91527
91528goog.exportProperty(
91529 ol.interaction.Modify.Event.prototype,
91530 'preventDefault',
91531 ol.interaction.Modify.Event.prototype.preventDefault);
91532
91533goog.exportProperty(
91534 ol.interaction.Modify.Event.prototype,
91535 'stopPropagation',
91536 ol.interaction.Modify.Event.prototype.stopPropagation);
91537
91538goog.exportProperty(
91539 ol.interaction.MouseWheelZoom.prototype,
91540 'getActive',
91541 ol.interaction.MouseWheelZoom.prototype.getActive);
91542
91543goog.exportProperty(
91544 ol.interaction.MouseWheelZoom.prototype,
91545 'getMap',
91546 ol.interaction.MouseWheelZoom.prototype.getMap);
91547
91548goog.exportProperty(
91549 ol.interaction.MouseWheelZoom.prototype,
91550 'setActive',
91551 ol.interaction.MouseWheelZoom.prototype.setActive);
91552
91553goog.exportProperty(
91554 ol.interaction.MouseWheelZoom.prototype,
91555 'get',
91556 ol.interaction.MouseWheelZoom.prototype.get);
91557
91558goog.exportProperty(
91559 ol.interaction.MouseWheelZoom.prototype,
91560 'getKeys',
91561 ol.interaction.MouseWheelZoom.prototype.getKeys);
91562
91563goog.exportProperty(
91564 ol.interaction.MouseWheelZoom.prototype,
91565 'getProperties',
91566 ol.interaction.MouseWheelZoom.prototype.getProperties);
91567
91568goog.exportProperty(
91569 ol.interaction.MouseWheelZoom.prototype,
91570 'set',
91571 ol.interaction.MouseWheelZoom.prototype.set);
91572
91573goog.exportProperty(
91574 ol.interaction.MouseWheelZoom.prototype,
91575 'setProperties',
91576 ol.interaction.MouseWheelZoom.prototype.setProperties);
91577
91578goog.exportProperty(
91579 ol.interaction.MouseWheelZoom.prototype,
91580 'unset',
91581 ol.interaction.MouseWheelZoom.prototype.unset);
91582
91583goog.exportProperty(
91584 ol.interaction.MouseWheelZoom.prototype,
91585 'changed',
91586 ol.interaction.MouseWheelZoom.prototype.changed);
91587
91588goog.exportProperty(
91589 ol.interaction.MouseWheelZoom.prototype,
91590 'dispatchEvent',
91591 ol.interaction.MouseWheelZoom.prototype.dispatchEvent);
91592
91593goog.exportProperty(
91594 ol.interaction.MouseWheelZoom.prototype,
91595 'getRevision',
91596 ol.interaction.MouseWheelZoom.prototype.getRevision);
91597
91598goog.exportProperty(
91599 ol.interaction.MouseWheelZoom.prototype,
91600 'on',
91601 ol.interaction.MouseWheelZoom.prototype.on);
91602
91603goog.exportProperty(
91604 ol.interaction.MouseWheelZoom.prototype,
91605 'once',
91606 ol.interaction.MouseWheelZoom.prototype.once);
91607
91608goog.exportProperty(
91609 ol.interaction.MouseWheelZoom.prototype,
91610 'un',
91611 ol.interaction.MouseWheelZoom.prototype.un);
91612
91613goog.exportProperty(
91614 ol.interaction.PinchRotate.prototype,
91615 'getActive',
91616 ol.interaction.PinchRotate.prototype.getActive);
91617
91618goog.exportProperty(
91619 ol.interaction.PinchRotate.prototype,
91620 'getMap',
91621 ol.interaction.PinchRotate.prototype.getMap);
91622
91623goog.exportProperty(
91624 ol.interaction.PinchRotate.prototype,
91625 'setActive',
91626 ol.interaction.PinchRotate.prototype.setActive);
91627
91628goog.exportProperty(
91629 ol.interaction.PinchRotate.prototype,
91630 'get',
91631 ol.interaction.PinchRotate.prototype.get);
91632
91633goog.exportProperty(
91634 ol.interaction.PinchRotate.prototype,
91635 'getKeys',
91636 ol.interaction.PinchRotate.prototype.getKeys);
91637
91638goog.exportProperty(
91639 ol.interaction.PinchRotate.prototype,
91640 'getProperties',
91641 ol.interaction.PinchRotate.prototype.getProperties);
91642
91643goog.exportProperty(
91644 ol.interaction.PinchRotate.prototype,
91645 'set',
91646 ol.interaction.PinchRotate.prototype.set);
91647
91648goog.exportProperty(
91649 ol.interaction.PinchRotate.prototype,
91650 'setProperties',
91651 ol.interaction.PinchRotate.prototype.setProperties);
91652
91653goog.exportProperty(
91654 ol.interaction.PinchRotate.prototype,
91655 'unset',
91656 ol.interaction.PinchRotate.prototype.unset);
91657
91658goog.exportProperty(
91659 ol.interaction.PinchRotate.prototype,
91660 'changed',
91661 ol.interaction.PinchRotate.prototype.changed);
91662
91663goog.exportProperty(
91664 ol.interaction.PinchRotate.prototype,
91665 'dispatchEvent',
91666 ol.interaction.PinchRotate.prototype.dispatchEvent);
91667
91668goog.exportProperty(
91669 ol.interaction.PinchRotate.prototype,
91670 'getRevision',
91671 ol.interaction.PinchRotate.prototype.getRevision);
91672
91673goog.exportProperty(
91674 ol.interaction.PinchRotate.prototype,
91675 'on',
91676 ol.interaction.PinchRotate.prototype.on);
91677
91678goog.exportProperty(
91679 ol.interaction.PinchRotate.prototype,
91680 'once',
91681 ol.interaction.PinchRotate.prototype.once);
91682
91683goog.exportProperty(
91684 ol.interaction.PinchRotate.prototype,
91685 'un',
91686 ol.interaction.PinchRotate.prototype.un);
91687
91688goog.exportProperty(
91689 ol.interaction.PinchZoom.prototype,
91690 'getActive',
91691 ol.interaction.PinchZoom.prototype.getActive);
91692
91693goog.exportProperty(
91694 ol.interaction.PinchZoom.prototype,
91695 'getMap',
91696 ol.interaction.PinchZoom.prototype.getMap);
91697
91698goog.exportProperty(
91699 ol.interaction.PinchZoom.prototype,
91700 'setActive',
91701 ol.interaction.PinchZoom.prototype.setActive);
91702
91703goog.exportProperty(
91704 ol.interaction.PinchZoom.prototype,
91705 'get',
91706 ol.interaction.PinchZoom.prototype.get);
91707
91708goog.exportProperty(
91709 ol.interaction.PinchZoom.prototype,
91710 'getKeys',
91711 ol.interaction.PinchZoom.prototype.getKeys);
91712
91713goog.exportProperty(
91714 ol.interaction.PinchZoom.prototype,
91715 'getProperties',
91716 ol.interaction.PinchZoom.prototype.getProperties);
91717
91718goog.exportProperty(
91719 ol.interaction.PinchZoom.prototype,
91720 'set',
91721 ol.interaction.PinchZoom.prototype.set);
91722
91723goog.exportProperty(
91724 ol.interaction.PinchZoom.prototype,
91725 'setProperties',
91726 ol.interaction.PinchZoom.prototype.setProperties);
91727
91728goog.exportProperty(
91729 ol.interaction.PinchZoom.prototype,
91730 'unset',
91731 ol.interaction.PinchZoom.prototype.unset);
91732
91733goog.exportProperty(
91734 ol.interaction.PinchZoom.prototype,
91735 'changed',
91736 ol.interaction.PinchZoom.prototype.changed);
91737
91738goog.exportProperty(
91739 ol.interaction.PinchZoom.prototype,
91740 'dispatchEvent',
91741 ol.interaction.PinchZoom.prototype.dispatchEvent);
91742
91743goog.exportProperty(
91744 ol.interaction.PinchZoom.prototype,
91745 'getRevision',
91746 ol.interaction.PinchZoom.prototype.getRevision);
91747
91748goog.exportProperty(
91749 ol.interaction.PinchZoom.prototype,
91750 'on',
91751 ol.interaction.PinchZoom.prototype.on);
91752
91753goog.exportProperty(
91754 ol.interaction.PinchZoom.prototype,
91755 'once',
91756 ol.interaction.PinchZoom.prototype.once);
91757
91758goog.exportProperty(
91759 ol.interaction.PinchZoom.prototype,
91760 'un',
91761 ol.interaction.PinchZoom.prototype.un);
91762
91763goog.exportProperty(
91764 ol.interaction.Select.prototype,
91765 'getActive',
91766 ol.interaction.Select.prototype.getActive);
91767
91768goog.exportProperty(
91769 ol.interaction.Select.prototype,
91770 'getMap',
91771 ol.interaction.Select.prototype.getMap);
91772
91773goog.exportProperty(
91774 ol.interaction.Select.prototype,
91775 'setActive',
91776 ol.interaction.Select.prototype.setActive);
91777
91778goog.exportProperty(
91779 ol.interaction.Select.prototype,
91780 'get',
91781 ol.interaction.Select.prototype.get);
91782
91783goog.exportProperty(
91784 ol.interaction.Select.prototype,
91785 'getKeys',
91786 ol.interaction.Select.prototype.getKeys);
91787
91788goog.exportProperty(
91789 ol.interaction.Select.prototype,
91790 'getProperties',
91791 ol.interaction.Select.prototype.getProperties);
91792
91793goog.exportProperty(
91794 ol.interaction.Select.prototype,
91795 'set',
91796 ol.interaction.Select.prototype.set);
91797
91798goog.exportProperty(
91799 ol.interaction.Select.prototype,
91800 'setProperties',
91801 ol.interaction.Select.prototype.setProperties);
91802
91803goog.exportProperty(
91804 ol.interaction.Select.prototype,
91805 'unset',
91806 ol.interaction.Select.prototype.unset);
91807
91808goog.exportProperty(
91809 ol.interaction.Select.prototype,
91810 'changed',
91811 ol.interaction.Select.prototype.changed);
91812
91813goog.exportProperty(
91814 ol.interaction.Select.prototype,
91815 'dispatchEvent',
91816 ol.interaction.Select.prototype.dispatchEvent);
91817
91818goog.exportProperty(
91819 ol.interaction.Select.prototype,
91820 'getRevision',
91821 ol.interaction.Select.prototype.getRevision);
91822
91823goog.exportProperty(
91824 ol.interaction.Select.prototype,
91825 'on',
91826 ol.interaction.Select.prototype.on);
91827
91828goog.exportProperty(
91829 ol.interaction.Select.prototype,
91830 'once',
91831 ol.interaction.Select.prototype.once);
91832
91833goog.exportProperty(
91834 ol.interaction.Select.prototype,
91835 'un',
91836 ol.interaction.Select.prototype.un);
91837
91838goog.exportProperty(
91839 ol.interaction.Select.Event.prototype,
91840 'type',
91841 ol.interaction.Select.Event.prototype.type);
91842
91843goog.exportProperty(
91844 ol.interaction.Select.Event.prototype,
91845 'target',
91846 ol.interaction.Select.Event.prototype.target);
91847
91848goog.exportProperty(
91849 ol.interaction.Select.Event.prototype,
91850 'preventDefault',
91851 ol.interaction.Select.Event.prototype.preventDefault);
91852
91853goog.exportProperty(
91854 ol.interaction.Select.Event.prototype,
91855 'stopPropagation',
91856 ol.interaction.Select.Event.prototype.stopPropagation);
91857
91858goog.exportProperty(
91859 ol.interaction.Snap.prototype,
91860 'getActive',
91861 ol.interaction.Snap.prototype.getActive);
91862
91863goog.exportProperty(
91864 ol.interaction.Snap.prototype,
91865 'getMap',
91866 ol.interaction.Snap.prototype.getMap);
91867
91868goog.exportProperty(
91869 ol.interaction.Snap.prototype,
91870 'setActive',
91871 ol.interaction.Snap.prototype.setActive);
91872
91873goog.exportProperty(
91874 ol.interaction.Snap.prototype,
91875 'get',
91876 ol.interaction.Snap.prototype.get);
91877
91878goog.exportProperty(
91879 ol.interaction.Snap.prototype,
91880 'getKeys',
91881 ol.interaction.Snap.prototype.getKeys);
91882
91883goog.exportProperty(
91884 ol.interaction.Snap.prototype,
91885 'getProperties',
91886 ol.interaction.Snap.prototype.getProperties);
91887
91888goog.exportProperty(
91889 ol.interaction.Snap.prototype,
91890 'set',
91891 ol.interaction.Snap.prototype.set);
91892
91893goog.exportProperty(
91894 ol.interaction.Snap.prototype,
91895 'setProperties',
91896 ol.interaction.Snap.prototype.setProperties);
91897
91898goog.exportProperty(
91899 ol.interaction.Snap.prototype,
91900 'unset',
91901 ol.interaction.Snap.prototype.unset);
91902
91903goog.exportProperty(
91904 ol.interaction.Snap.prototype,
91905 'changed',
91906 ol.interaction.Snap.prototype.changed);
91907
91908goog.exportProperty(
91909 ol.interaction.Snap.prototype,
91910 'dispatchEvent',
91911 ol.interaction.Snap.prototype.dispatchEvent);
91912
91913goog.exportProperty(
91914 ol.interaction.Snap.prototype,
91915 'getRevision',
91916 ol.interaction.Snap.prototype.getRevision);
91917
91918goog.exportProperty(
91919 ol.interaction.Snap.prototype,
91920 'on',
91921 ol.interaction.Snap.prototype.on);
91922
91923goog.exportProperty(
91924 ol.interaction.Snap.prototype,
91925 'once',
91926 ol.interaction.Snap.prototype.once);
91927
91928goog.exportProperty(
91929 ol.interaction.Snap.prototype,
91930 'un',
91931 ol.interaction.Snap.prototype.un);
91932
91933goog.exportProperty(
91934 ol.interaction.Translate.prototype,
91935 'getActive',
91936 ol.interaction.Translate.prototype.getActive);
91937
91938goog.exportProperty(
91939 ol.interaction.Translate.prototype,
91940 'getMap',
91941 ol.interaction.Translate.prototype.getMap);
91942
91943goog.exportProperty(
91944 ol.interaction.Translate.prototype,
91945 'setActive',
91946 ol.interaction.Translate.prototype.setActive);
91947
91948goog.exportProperty(
91949 ol.interaction.Translate.prototype,
91950 'get',
91951 ol.interaction.Translate.prototype.get);
91952
91953goog.exportProperty(
91954 ol.interaction.Translate.prototype,
91955 'getKeys',
91956 ol.interaction.Translate.prototype.getKeys);
91957
91958goog.exportProperty(
91959 ol.interaction.Translate.prototype,
91960 'getProperties',
91961 ol.interaction.Translate.prototype.getProperties);
91962
91963goog.exportProperty(
91964 ol.interaction.Translate.prototype,
91965 'set',
91966 ol.interaction.Translate.prototype.set);
91967
91968goog.exportProperty(
91969 ol.interaction.Translate.prototype,
91970 'setProperties',
91971 ol.interaction.Translate.prototype.setProperties);
91972
91973goog.exportProperty(
91974 ol.interaction.Translate.prototype,
91975 'unset',
91976 ol.interaction.Translate.prototype.unset);
91977
91978goog.exportProperty(
91979 ol.interaction.Translate.prototype,
91980 'changed',
91981 ol.interaction.Translate.prototype.changed);
91982
91983goog.exportProperty(
91984 ol.interaction.Translate.prototype,
91985 'dispatchEvent',
91986 ol.interaction.Translate.prototype.dispatchEvent);
91987
91988goog.exportProperty(
91989 ol.interaction.Translate.prototype,
91990 'getRevision',
91991 ol.interaction.Translate.prototype.getRevision);
91992
91993goog.exportProperty(
91994 ol.interaction.Translate.prototype,
91995 'on',
91996 ol.interaction.Translate.prototype.on);
91997
91998goog.exportProperty(
91999 ol.interaction.Translate.prototype,
92000 'once',
92001 ol.interaction.Translate.prototype.once);
92002
92003goog.exportProperty(
92004 ol.interaction.Translate.prototype,
92005 'un',
92006 ol.interaction.Translate.prototype.un);
92007
92008goog.exportProperty(
92009 ol.interaction.Translate.Event.prototype,
92010 'type',
92011 ol.interaction.Translate.Event.prototype.type);
92012
92013goog.exportProperty(
92014 ol.interaction.Translate.Event.prototype,
92015 'target',
92016 ol.interaction.Translate.Event.prototype.target);
92017
92018goog.exportProperty(
92019 ol.interaction.Translate.Event.prototype,
92020 'preventDefault',
92021 ol.interaction.Translate.Event.prototype.preventDefault);
92022
92023goog.exportProperty(
92024 ol.interaction.Translate.Event.prototype,
92025 'stopPropagation',
92026 ol.interaction.Translate.Event.prototype.stopPropagation);
92027
92028goog.exportProperty(
92029 ol.geom.Geometry.prototype,
92030 'get',
92031 ol.geom.Geometry.prototype.get);
92032
92033goog.exportProperty(
92034 ol.geom.Geometry.prototype,
92035 'getKeys',
92036 ol.geom.Geometry.prototype.getKeys);
92037
92038goog.exportProperty(
92039 ol.geom.Geometry.prototype,
92040 'getProperties',
92041 ol.geom.Geometry.prototype.getProperties);
92042
92043goog.exportProperty(
92044 ol.geom.Geometry.prototype,
92045 'set',
92046 ol.geom.Geometry.prototype.set);
92047
92048goog.exportProperty(
92049 ol.geom.Geometry.prototype,
92050 'setProperties',
92051 ol.geom.Geometry.prototype.setProperties);
92052
92053goog.exportProperty(
92054 ol.geom.Geometry.prototype,
92055 'unset',
92056 ol.geom.Geometry.prototype.unset);
92057
92058goog.exportProperty(
92059 ol.geom.Geometry.prototype,
92060 'changed',
92061 ol.geom.Geometry.prototype.changed);
92062
92063goog.exportProperty(
92064 ol.geom.Geometry.prototype,
92065 'dispatchEvent',
92066 ol.geom.Geometry.prototype.dispatchEvent);
92067
92068goog.exportProperty(
92069 ol.geom.Geometry.prototype,
92070 'getRevision',
92071 ol.geom.Geometry.prototype.getRevision);
92072
92073goog.exportProperty(
92074 ol.geom.Geometry.prototype,
92075 'on',
92076 ol.geom.Geometry.prototype.on);
92077
92078goog.exportProperty(
92079 ol.geom.Geometry.prototype,
92080 'once',
92081 ol.geom.Geometry.prototype.once);
92082
92083goog.exportProperty(
92084 ol.geom.Geometry.prototype,
92085 'un',
92086 ol.geom.Geometry.prototype.un);
92087
92088goog.exportProperty(
92089 ol.geom.SimpleGeometry.prototype,
92090 'getClosestPoint',
92091 ol.geom.SimpleGeometry.prototype.getClosestPoint);
92092
92093goog.exportProperty(
92094 ol.geom.SimpleGeometry.prototype,
92095 'intersectsCoordinate',
92096 ol.geom.SimpleGeometry.prototype.intersectsCoordinate);
92097
92098goog.exportProperty(
92099 ol.geom.SimpleGeometry.prototype,
92100 'getExtent',
92101 ol.geom.SimpleGeometry.prototype.getExtent);
92102
92103goog.exportProperty(
92104 ol.geom.SimpleGeometry.prototype,
92105 'rotate',
92106 ol.geom.SimpleGeometry.prototype.rotate);
92107
92108goog.exportProperty(
92109 ol.geom.SimpleGeometry.prototype,
92110 'scale',
92111 ol.geom.SimpleGeometry.prototype.scale);
92112
92113goog.exportProperty(
92114 ol.geom.SimpleGeometry.prototype,
92115 'simplify',
92116 ol.geom.SimpleGeometry.prototype.simplify);
92117
92118goog.exportProperty(
92119 ol.geom.SimpleGeometry.prototype,
92120 'transform',
92121 ol.geom.SimpleGeometry.prototype.transform);
92122
92123goog.exportProperty(
92124 ol.geom.SimpleGeometry.prototype,
92125 'get',
92126 ol.geom.SimpleGeometry.prototype.get);
92127
92128goog.exportProperty(
92129 ol.geom.SimpleGeometry.prototype,
92130 'getKeys',
92131 ol.geom.SimpleGeometry.prototype.getKeys);
92132
92133goog.exportProperty(
92134 ol.geom.SimpleGeometry.prototype,
92135 'getProperties',
92136 ol.geom.SimpleGeometry.prototype.getProperties);
92137
92138goog.exportProperty(
92139 ol.geom.SimpleGeometry.prototype,
92140 'set',
92141 ol.geom.SimpleGeometry.prototype.set);
92142
92143goog.exportProperty(
92144 ol.geom.SimpleGeometry.prototype,
92145 'setProperties',
92146 ol.geom.SimpleGeometry.prototype.setProperties);
92147
92148goog.exportProperty(
92149 ol.geom.SimpleGeometry.prototype,
92150 'unset',
92151 ol.geom.SimpleGeometry.prototype.unset);
92152
92153goog.exportProperty(
92154 ol.geom.SimpleGeometry.prototype,
92155 'changed',
92156 ol.geom.SimpleGeometry.prototype.changed);
92157
92158goog.exportProperty(
92159 ol.geom.SimpleGeometry.prototype,
92160 'dispatchEvent',
92161 ol.geom.SimpleGeometry.prototype.dispatchEvent);
92162
92163goog.exportProperty(
92164 ol.geom.SimpleGeometry.prototype,
92165 'getRevision',
92166 ol.geom.SimpleGeometry.prototype.getRevision);
92167
92168goog.exportProperty(
92169 ol.geom.SimpleGeometry.prototype,
92170 'on',
92171 ol.geom.SimpleGeometry.prototype.on);
92172
92173goog.exportProperty(
92174 ol.geom.SimpleGeometry.prototype,
92175 'once',
92176 ol.geom.SimpleGeometry.prototype.once);
92177
92178goog.exportProperty(
92179 ol.geom.SimpleGeometry.prototype,
92180 'un',
92181 ol.geom.SimpleGeometry.prototype.un);
92182
92183goog.exportProperty(
92184 ol.geom.Circle.prototype,
92185 'getFirstCoordinate',
92186 ol.geom.Circle.prototype.getFirstCoordinate);
92187
92188goog.exportProperty(
92189 ol.geom.Circle.prototype,
92190 'getLastCoordinate',
92191 ol.geom.Circle.prototype.getLastCoordinate);
92192
92193goog.exportProperty(
92194 ol.geom.Circle.prototype,
92195 'getLayout',
92196 ol.geom.Circle.prototype.getLayout);
92197
92198goog.exportProperty(
92199 ol.geom.Circle.prototype,
92200 'rotate',
92201 ol.geom.Circle.prototype.rotate);
92202
92203goog.exportProperty(
92204 ol.geom.Circle.prototype,
92205 'scale',
92206 ol.geom.Circle.prototype.scale);
92207
92208goog.exportProperty(
92209 ol.geom.Circle.prototype,
92210 'getClosestPoint',
92211 ol.geom.Circle.prototype.getClosestPoint);
92212
92213goog.exportProperty(
92214 ol.geom.Circle.prototype,
92215 'intersectsCoordinate',
92216 ol.geom.Circle.prototype.intersectsCoordinate);
92217
92218goog.exportProperty(
92219 ol.geom.Circle.prototype,
92220 'getExtent',
92221 ol.geom.Circle.prototype.getExtent);
92222
92223goog.exportProperty(
92224 ol.geom.Circle.prototype,
92225 'simplify',
92226 ol.geom.Circle.prototype.simplify);
92227
92228goog.exportProperty(
92229 ol.geom.Circle.prototype,
92230 'get',
92231 ol.geom.Circle.prototype.get);
92232
92233goog.exportProperty(
92234 ol.geom.Circle.prototype,
92235 'getKeys',
92236 ol.geom.Circle.prototype.getKeys);
92237
92238goog.exportProperty(
92239 ol.geom.Circle.prototype,
92240 'getProperties',
92241 ol.geom.Circle.prototype.getProperties);
92242
92243goog.exportProperty(
92244 ol.geom.Circle.prototype,
92245 'set',
92246 ol.geom.Circle.prototype.set);
92247
92248goog.exportProperty(
92249 ol.geom.Circle.prototype,
92250 'setProperties',
92251 ol.geom.Circle.prototype.setProperties);
92252
92253goog.exportProperty(
92254 ol.geom.Circle.prototype,
92255 'unset',
92256 ol.geom.Circle.prototype.unset);
92257
92258goog.exportProperty(
92259 ol.geom.Circle.prototype,
92260 'changed',
92261 ol.geom.Circle.prototype.changed);
92262
92263goog.exportProperty(
92264 ol.geom.Circle.prototype,
92265 'dispatchEvent',
92266 ol.geom.Circle.prototype.dispatchEvent);
92267
92268goog.exportProperty(
92269 ol.geom.Circle.prototype,
92270 'getRevision',
92271 ol.geom.Circle.prototype.getRevision);
92272
92273goog.exportProperty(
92274 ol.geom.Circle.prototype,
92275 'on',
92276 ol.geom.Circle.prototype.on);
92277
92278goog.exportProperty(
92279 ol.geom.Circle.prototype,
92280 'once',
92281 ol.geom.Circle.prototype.once);
92282
92283goog.exportProperty(
92284 ol.geom.Circle.prototype,
92285 'un',
92286 ol.geom.Circle.prototype.un);
92287
92288goog.exportProperty(
92289 ol.geom.GeometryCollection.prototype,
92290 'getClosestPoint',
92291 ol.geom.GeometryCollection.prototype.getClosestPoint);
92292
92293goog.exportProperty(
92294 ol.geom.GeometryCollection.prototype,
92295 'intersectsCoordinate',
92296 ol.geom.GeometryCollection.prototype.intersectsCoordinate);
92297
92298goog.exportProperty(
92299 ol.geom.GeometryCollection.prototype,
92300 'getExtent',
92301 ol.geom.GeometryCollection.prototype.getExtent);
92302
92303goog.exportProperty(
92304 ol.geom.GeometryCollection.prototype,
92305 'rotate',
92306 ol.geom.GeometryCollection.prototype.rotate);
92307
92308goog.exportProperty(
92309 ol.geom.GeometryCollection.prototype,
92310 'scale',
92311 ol.geom.GeometryCollection.prototype.scale);
92312
92313goog.exportProperty(
92314 ol.geom.GeometryCollection.prototype,
92315 'simplify',
92316 ol.geom.GeometryCollection.prototype.simplify);
92317
92318goog.exportProperty(
92319 ol.geom.GeometryCollection.prototype,
92320 'transform',
92321 ol.geom.GeometryCollection.prototype.transform);
92322
92323goog.exportProperty(
92324 ol.geom.GeometryCollection.prototype,
92325 'get',
92326 ol.geom.GeometryCollection.prototype.get);
92327
92328goog.exportProperty(
92329 ol.geom.GeometryCollection.prototype,
92330 'getKeys',
92331 ol.geom.GeometryCollection.prototype.getKeys);
92332
92333goog.exportProperty(
92334 ol.geom.GeometryCollection.prototype,
92335 'getProperties',
92336 ol.geom.GeometryCollection.prototype.getProperties);
92337
92338goog.exportProperty(
92339 ol.geom.GeometryCollection.prototype,
92340 'set',
92341 ol.geom.GeometryCollection.prototype.set);
92342
92343goog.exportProperty(
92344 ol.geom.GeometryCollection.prototype,
92345 'setProperties',
92346 ol.geom.GeometryCollection.prototype.setProperties);
92347
92348goog.exportProperty(
92349 ol.geom.GeometryCollection.prototype,
92350 'unset',
92351 ol.geom.GeometryCollection.prototype.unset);
92352
92353goog.exportProperty(
92354 ol.geom.GeometryCollection.prototype,
92355 'changed',
92356 ol.geom.GeometryCollection.prototype.changed);
92357
92358goog.exportProperty(
92359 ol.geom.GeometryCollection.prototype,
92360 'dispatchEvent',
92361 ol.geom.GeometryCollection.prototype.dispatchEvent);
92362
92363goog.exportProperty(
92364 ol.geom.GeometryCollection.prototype,
92365 'getRevision',
92366 ol.geom.GeometryCollection.prototype.getRevision);
92367
92368goog.exportProperty(
92369 ol.geom.GeometryCollection.prototype,
92370 'on',
92371 ol.geom.GeometryCollection.prototype.on);
92372
92373goog.exportProperty(
92374 ol.geom.GeometryCollection.prototype,
92375 'once',
92376 ol.geom.GeometryCollection.prototype.once);
92377
92378goog.exportProperty(
92379 ol.geom.GeometryCollection.prototype,
92380 'un',
92381 ol.geom.GeometryCollection.prototype.un);
92382
92383goog.exportProperty(
92384 ol.geom.LinearRing.prototype,
92385 'getFirstCoordinate',
92386 ol.geom.LinearRing.prototype.getFirstCoordinate);
92387
92388goog.exportProperty(
92389 ol.geom.LinearRing.prototype,
92390 'getLastCoordinate',
92391 ol.geom.LinearRing.prototype.getLastCoordinate);
92392
92393goog.exportProperty(
92394 ol.geom.LinearRing.prototype,
92395 'getLayout',
92396 ol.geom.LinearRing.prototype.getLayout);
92397
92398goog.exportProperty(
92399 ol.geom.LinearRing.prototype,
92400 'rotate',
92401 ol.geom.LinearRing.prototype.rotate);
92402
92403goog.exportProperty(
92404 ol.geom.LinearRing.prototype,
92405 'scale',
92406 ol.geom.LinearRing.prototype.scale);
92407
92408goog.exportProperty(
92409 ol.geom.LinearRing.prototype,
92410 'getClosestPoint',
92411 ol.geom.LinearRing.prototype.getClosestPoint);
92412
92413goog.exportProperty(
92414 ol.geom.LinearRing.prototype,
92415 'intersectsCoordinate',
92416 ol.geom.LinearRing.prototype.intersectsCoordinate);
92417
92418goog.exportProperty(
92419 ol.geom.LinearRing.prototype,
92420 'getExtent',
92421 ol.geom.LinearRing.prototype.getExtent);
92422
92423goog.exportProperty(
92424 ol.geom.LinearRing.prototype,
92425 'simplify',
92426 ol.geom.LinearRing.prototype.simplify);
92427
92428goog.exportProperty(
92429 ol.geom.LinearRing.prototype,
92430 'transform',
92431 ol.geom.LinearRing.prototype.transform);
92432
92433goog.exportProperty(
92434 ol.geom.LinearRing.prototype,
92435 'get',
92436 ol.geom.LinearRing.prototype.get);
92437
92438goog.exportProperty(
92439 ol.geom.LinearRing.prototype,
92440 'getKeys',
92441 ol.geom.LinearRing.prototype.getKeys);
92442
92443goog.exportProperty(
92444 ol.geom.LinearRing.prototype,
92445 'getProperties',
92446 ol.geom.LinearRing.prototype.getProperties);
92447
92448goog.exportProperty(
92449 ol.geom.LinearRing.prototype,
92450 'set',
92451 ol.geom.LinearRing.prototype.set);
92452
92453goog.exportProperty(
92454 ol.geom.LinearRing.prototype,
92455 'setProperties',
92456 ol.geom.LinearRing.prototype.setProperties);
92457
92458goog.exportProperty(
92459 ol.geom.LinearRing.prototype,
92460 'unset',
92461 ol.geom.LinearRing.prototype.unset);
92462
92463goog.exportProperty(
92464 ol.geom.LinearRing.prototype,
92465 'changed',
92466 ol.geom.LinearRing.prototype.changed);
92467
92468goog.exportProperty(
92469 ol.geom.LinearRing.prototype,
92470 'dispatchEvent',
92471 ol.geom.LinearRing.prototype.dispatchEvent);
92472
92473goog.exportProperty(
92474 ol.geom.LinearRing.prototype,
92475 'getRevision',
92476 ol.geom.LinearRing.prototype.getRevision);
92477
92478goog.exportProperty(
92479 ol.geom.LinearRing.prototype,
92480 'on',
92481 ol.geom.LinearRing.prototype.on);
92482
92483goog.exportProperty(
92484 ol.geom.LinearRing.prototype,
92485 'once',
92486 ol.geom.LinearRing.prototype.once);
92487
92488goog.exportProperty(
92489 ol.geom.LinearRing.prototype,
92490 'un',
92491 ol.geom.LinearRing.prototype.un);
92492
92493goog.exportProperty(
92494 ol.geom.LineString.prototype,
92495 'getFirstCoordinate',
92496 ol.geom.LineString.prototype.getFirstCoordinate);
92497
92498goog.exportProperty(
92499 ol.geom.LineString.prototype,
92500 'getLastCoordinate',
92501 ol.geom.LineString.prototype.getLastCoordinate);
92502
92503goog.exportProperty(
92504 ol.geom.LineString.prototype,
92505 'getLayout',
92506 ol.geom.LineString.prototype.getLayout);
92507
92508goog.exportProperty(
92509 ol.geom.LineString.prototype,
92510 'rotate',
92511 ol.geom.LineString.prototype.rotate);
92512
92513goog.exportProperty(
92514 ol.geom.LineString.prototype,
92515 'scale',
92516 ol.geom.LineString.prototype.scale);
92517
92518goog.exportProperty(
92519 ol.geom.LineString.prototype,
92520 'getClosestPoint',
92521 ol.geom.LineString.prototype.getClosestPoint);
92522
92523goog.exportProperty(
92524 ol.geom.LineString.prototype,
92525 'intersectsCoordinate',
92526 ol.geom.LineString.prototype.intersectsCoordinate);
92527
92528goog.exportProperty(
92529 ol.geom.LineString.prototype,
92530 'getExtent',
92531 ol.geom.LineString.prototype.getExtent);
92532
92533goog.exportProperty(
92534 ol.geom.LineString.prototype,
92535 'simplify',
92536 ol.geom.LineString.prototype.simplify);
92537
92538goog.exportProperty(
92539 ol.geom.LineString.prototype,
92540 'transform',
92541 ol.geom.LineString.prototype.transform);
92542
92543goog.exportProperty(
92544 ol.geom.LineString.prototype,
92545 'get',
92546 ol.geom.LineString.prototype.get);
92547
92548goog.exportProperty(
92549 ol.geom.LineString.prototype,
92550 'getKeys',
92551 ol.geom.LineString.prototype.getKeys);
92552
92553goog.exportProperty(
92554 ol.geom.LineString.prototype,
92555 'getProperties',
92556 ol.geom.LineString.prototype.getProperties);
92557
92558goog.exportProperty(
92559 ol.geom.LineString.prototype,
92560 'set',
92561 ol.geom.LineString.prototype.set);
92562
92563goog.exportProperty(
92564 ol.geom.LineString.prototype,
92565 'setProperties',
92566 ol.geom.LineString.prototype.setProperties);
92567
92568goog.exportProperty(
92569 ol.geom.LineString.prototype,
92570 'unset',
92571 ol.geom.LineString.prototype.unset);
92572
92573goog.exportProperty(
92574 ol.geom.LineString.prototype,
92575 'changed',
92576 ol.geom.LineString.prototype.changed);
92577
92578goog.exportProperty(
92579 ol.geom.LineString.prototype,
92580 'dispatchEvent',
92581 ol.geom.LineString.prototype.dispatchEvent);
92582
92583goog.exportProperty(
92584 ol.geom.LineString.prototype,
92585 'getRevision',
92586 ol.geom.LineString.prototype.getRevision);
92587
92588goog.exportProperty(
92589 ol.geom.LineString.prototype,
92590 'on',
92591 ol.geom.LineString.prototype.on);
92592
92593goog.exportProperty(
92594 ol.geom.LineString.prototype,
92595 'once',
92596 ol.geom.LineString.prototype.once);
92597
92598goog.exportProperty(
92599 ol.geom.LineString.prototype,
92600 'un',
92601 ol.geom.LineString.prototype.un);
92602
92603goog.exportProperty(
92604 ol.geom.MultiLineString.prototype,
92605 'getFirstCoordinate',
92606 ol.geom.MultiLineString.prototype.getFirstCoordinate);
92607
92608goog.exportProperty(
92609 ol.geom.MultiLineString.prototype,
92610 'getLastCoordinate',
92611 ol.geom.MultiLineString.prototype.getLastCoordinate);
92612
92613goog.exportProperty(
92614 ol.geom.MultiLineString.prototype,
92615 'getLayout',
92616 ol.geom.MultiLineString.prototype.getLayout);
92617
92618goog.exportProperty(
92619 ol.geom.MultiLineString.prototype,
92620 'rotate',
92621 ol.geom.MultiLineString.prototype.rotate);
92622
92623goog.exportProperty(
92624 ol.geom.MultiLineString.prototype,
92625 'scale',
92626 ol.geom.MultiLineString.prototype.scale);
92627
92628goog.exportProperty(
92629 ol.geom.MultiLineString.prototype,
92630 'getClosestPoint',
92631 ol.geom.MultiLineString.prototype.getClosestPoint);
92632
92633goog.exportProperty(
92634 ol.geom.MultiLineString.prototype,
92635 'intersectsCoordinate',
92636 ol.geom.MultiLineString.prototype.intersectsCoordinate);
92637
92638goog.exportProperty(
92639 ol.geom.MultiLineString.prototype,
92640 'getExtent',
92641 ol.geom.MultiLineString.prototype.getExtent);
92642
92643goog.exportProperty(
92644 ol.geom.MultiLineString.prototype,
92645 'simplify',
92646 ol.geom.MultiLineString.prototype.simplify);
92647
92648goog.exportProperty(
92649 ol.geom.MultiLineString.prototype,
92650 'transform',
92651 ol.geom.MultiLineString.prototype.transform);
92652
92653goog.exportProperty(
92654 ol.geom.MultiLineString.prototype,
92655 'get',
92656 ol.geom.MultiLineString.prototype.get);
92657
92658goog.exportProperty(
92659 ol.geom.MultiLineString.prototype,
92660 'getKeys',
92661 ol.geom.MultiLineString.prototype.getKeys);
92662
92663goog.exportProperty(
92664 ol.geom.MultiLineString.prototype,
92665 'getProperties',
92666 ol.geom.MultiLineString.prototype.getProperties);
92667
92668goog.exportProperty(
92669 ol.geom.MultiLineString.prototype,
92670 'set',
92671 ol.geom.MultiLineString.prototype.set);
92672
92673goog.exportProperty(
92674 ol.geom.MultiLineString.prototype,
92675 'setProperties',
92676 ol.geom.MultiLineString.prototype.setProperties);
92677
92678goog.exportProperty(
92679 ol.geom.MultiLineString.prototype,
92680 'unset',
92681 ol.geom.MultiLineString.prototype.unset);
92682
92683goog.exportProperty(
92684 ol.geom.MultiLineString.prototype,
92685 'changed',
92686 ol.geom.MultiLineString.prototype.changed);
92687
92688goog.exportProperty(
92689 ol.geom.MultiLineString.prototype,
92690 'dispatchEvent',
92691 ol.geom.MultiLineString.prototype.dispatchEvent);
92692
92693goog.exportProperty(
92694 ol.geom.MultiLineString.prototype,
92695 'getRevision',
92696 ol.geom.MultiLineString.prototype.getRevision);
92697
92698goog.exportProperty(
92699 ol.geom.MultiLineString.prototype,
92700 'on',
92701 ol.geom.MultiLineString.prototype.on);
92702
92703goog.exportProperty(
92704 ol.geom.MultiLineString.prototype,
92705 'once',
92706 ol.geom.MultiLineString.prototype.once);
92707
92708goog.exportProperty(
92709 ol.geom.MultiLineString.prototype,
92710 'un',
92711 ol.geom.MultiLineString.prototype.un);
92712
92713goog.exportProperty(
92714 ol.geom.MultiPoint.prototype,
92715 'getFirstCoordinate',
92716 ol.geom.MultiPoint.prototype.getFirstCoordinate);
92717
92718goog.exportProperty(
92719 ol.geom.MultiPoint.prototype,
92720 'getLastCoordinate',
92721 ol.geom.MultiPoint.prototype.getLastCoordinate);
92722
92723goog.exportProperty(
92724 ol.geom.MultiPoint.prototype,
92725 'getLayout',
92726 ol.geom.MultiPoint.prototype.getLayout);
92727
92728goog.exportProperty(
92729 ol.geom.MultiPoint.prototype,
92730 'rotate',
92731 ol.geom.MultiPoint.prototype.rotate);
92732
92733goog.exportProperty(
92734 ol.geom.MultiPoint.prototype,
92735 'scale',
92736 ol.geom.MultiPoint.prototype.scale);
92737
92738goog.exportProperty(
92739 ol.geom.MultiPoint.prototype,
92740 'getClosestPoint',
92741 ol.geom.MultiPoint.prototype.getClosestPoint);
92742
92743goog.exportProperty(
92744 ol.geom.MultiPoint.prototype,
92745 'intersectsCoordinate',
92746 ol.geom.MultiPoint.prototype.intersectsCoordinate);
92747
92748goog.exportProperty(
92749 ol.geom.MultiPoint.prototype,
92750 'getExtent',
92751 ol.geom.MultiPoint.prototype.getExtent);
92752
92753goog.exportProperty(
92754 ol.geom.MultiPoint.prototype,
92755 'simplify',
92756 ol.geom.MultiPoint.prototype.simplify);
92757
92758goog.exportProperty(
92759 ol.geom.MultiPoint.prototype,
92760 'transform',
92761 ol.geom.MultiPoint.prototype.transform);
92762
92763goog.exportProperty(
92764 ol.geom.MultiPoint.prototype,
92765 'get',
92766 ol.geom.MultiPoint.prototype.get);
92767
92768goog.exportProperty(
92769 ol.geom.MultiPoint.prototype,
92770 'getKeys',
92771 ol.geom.MultiPoint.prototype.getKeys);
92772
92773goog.exportProperty(
92774 ol.geom.MultiPoint.prototype,
92775 'getProperties',
92776 ol.geom.MultiPoint.prototype.getProperties);
92777
92778goog.exportProperty(
92779 ol.geom.MultiPoint.prototype,
92780 'set',
92781 ol.geom.MultiPoint.prototype.set);
92782
92783goog.exportProperty(
92784 ol.geom.MultiPoint.prototype,
92785 'setProperties',
92786 ol.geom.MultiPoint.prototype.setProperties);
92787
92788goog.exportProperty(
92789 ol.geom.MultiPoint.prototype,
92790 'unset',
92791 ol.geom.MultiPoint.prototype.unset);
92792
92793goog.exportProperty(
92794 ol.geom.MultiPoint.prototype,
92795 'changed',
92796 ol.geom.MultiPoint.prototype.changed);
92797
92798goog.exportProperty(
92799 ol.geom.MultiPoint.prototype,
92800 'dispatchEvent',
92801 ol.geom.MultiPoint.prototype.dispatchEvent);
92802
92803goog.exportProperty(
92804 ol.geom.MultiPoint.prototype,
92805 'getRevision',
92806 ol.geom.MultiPoint.prototype.getRevision);
92807
92808goog.exportProperty(
92809 ol.geom.MultiPoint.prototype,
92810 'on',
92811 ol.geom.MultiPoint.prototype.on);
92812
92813goog.exportProperty(
92814 ol.geom.MultiPoint.prototype,
92815 'once',
92816 ol.geom.MultiPoint.prototype.once);
92817
92818goog.exportProperty(
92819 ol.geom.MultiPoint.prototype,
92820 'un',
92821 ol.geom.MultiPoint.prototype.un);
92822
92823goog.exportProperty(
92824 ol.geom.MultiPolygon.prototype,
92825 'getFirstCoordinate',
92826 ol.geom.MultiPolygon.prototype.getFirstCoordinate);
92827
92828goog.exportProperty(
92829 ol.geom.MultiPolygon.prototype,
92830 'getLastCoordinate',
92831 ol.geom.MultiPolygon.prototype.getLastCoordinate);
92832
92833goog.exportProperty(
92834 ol.geom.MultiPolygon.prototype,
92835 'getLayout',
92836 ol.geom.MultiPolygon.prototype.getLayout);
92837
92838goog.exportProperty(
92839 ol.geom.MultiPolygon.prototype,
92840 'rotate',
92841 ol.geom.MultiPolygon.prototype.rotate);
92842
92843goog.exportProperty(
92844 ol.geom.MultiPolygon.prototype,
92845 'scale',
92846 ol.geom.MultiPolygon.prototype.scale);
92847
92848goog.exportProperty(
92849 ol.geom.MultiPolygon.prototype,
92850 'getClosestPoint',
92851 ol.geom.MultiPolygon.prototype.getClosestPoint);
92852
92853goog.exportProperty(
92854 ol.geom.MultiPolygon.prototype,
92855 'intersectsCoordinate',
92856 ol.geom.MultiPolygon.prototype.intersectsCoordinate);
92857
92858goog.exportProperty(
92859 ol.geom.MultiPolygon.prototype,
92860 'getExtent',
92861 ol.geom.MultiPolygon.prototype.getExtent);
92862
92863goog.exportProperty(
92864 ol.geom.MultiPolygon.prototype,
92865 'simplify',
92866 ol.geom.MultiPolygon.prototype.simplify);
92867
92868goog.exportProperty(
92869 ol.geom.MultiPolygon.prototype,
92870 'transform',
92871 ol.geom.MultiPolygon.prototype.transform);
92872
92873goog.exportProperty(
92874 ol.geom.MultiPolygon.prototype,
92875 'get',
92876 ol.geom.MultiPolygon.prototype.get);
92877
92878goog.exportProperty(
92879 ol.geom.MultiPolygon.prototype,
92880 'getKeys',
92881 ol.geom.MultiPolygon.prototype.getKeys);
92882
92883goog.exportProperty(
92884 ol.geom.MultiPolygon.prototype,
92885 'getProperties',
92886 ol.geom.MultiPolygon.prototype.getProperties);
92887
92888goog.exportProperty(
92889 ol.geom.MultiPolygon.prototype,
92890 'set',
92891 ol.geom.MultiPolygon.prototype.set);
92892
92893goog.exportProperty(
92894 ol.geom.MultiPolygon.prototype,
92895 'setProperties',
92896 ol.geom.MultiPolygon.prototype.setProperties);
92897
92898goog.exportProperty(
92899 ol.geom.MultiPolygon.prototype,
92900 'unset',
92901 ol.geom.MultiPolygon.prototype.unset);
92902
92903goog.exportProperty(
92904 ol.geom.MultiPolygon.prototype,
92905 'changed',
92906 ol.geom.MultiPolygon.prototype.changed);
92907
92908goog.exportProperty(
92909 ol.geom.MultiPolygon.prototype,
92910 'dispatchEvent',
92911 ol.geom.MultiPolygon.prototype.dispatchEvent);
92912
92913goog.exportProperty(
92914 ol.geom.MultiPolygon.prototype,
92915 'getRevision',
92916 ol.geom.MultiPolygon.prototype.getRevision);
92917
92918goog.exportProperty(
92919 ol.geom.MultiPolygon.prototype,
92920 'on',
92921 ol.geom.MultiPolygon.prototype.on);
92922
92923goog.exportProperty(
92924 ol.geom.MultiPolygon.prototype,
92925 'once',
92926 ol.geom.MultiPolygon.prototype.once);
92927
92928goog.exportProperty(
92929 ol.geom.MultiPolygon.prototype,
92930 'un',
92931 ol.geom.MultiPolygon.prototype.un);
92932
92933goog.exportProperty(
92934 ol.geom.Point.prototype,
92935 'getFirstCoordinate',
92936 ol.geom.Point.prototype.getFirstCoordinate);
92937
92938goog.exportProperty(
92939 ol.geom.Point.prototype,
92940 'getLastCoordinate',
92941 ol.geom.Point.prototype.getLastCoordinate);
92942
92943goog.exportProperty(
92944 ol.geom.Point.prototype,
92945 'getLayout',
92946 ol.geom.Point.prototype.getLayout);
92947
92948goog.exportProperty(
92949 ol.geom.Point.prototype,
92950 'rotate',
92951 ol.geom.Point.prototype.rotate);
92952
92953goog.exportProperty(
92954 ol.geom.Point.prototype,
92955 'scale',
92956 ol.geom.Point.prototype.scale);
92957
92958goog.exportProperty(
92959 ol.geom.Point.prototype,
92960 'getClosestPoint',
92961 ol.geom.Point.prototype.getClosestPoint);
92962
92963goog.exportProperty(
92964 ol.geom.Point.prototype,
92965 'intersectsCoordinate',
92966 ol.geom.Point.prototype.intersectsCoordinate);
92967
92968goog.exportProperty(
92969 ol.geom.Point.prototype,
92970 'getExtent',
92971 ol.geom.Point.prototype.getExtent);
92972
92973goog.exportProperty(
92974 ol.geom.Point.prototype,
92975 'simplify',
92976 ol.geom.Point.prototype.simplify);
92977
92978goog.exportProperty(
92979 ol.geom.Point.prototype,
92980 'transform',
92981 ol.geom.Point.prototype.transform);
92982
92983goog.exportProperty(
92984 ol.geom.Point.prototype,
92985 'get',
92986 ol.geom.Point.prototype.get);
92987
92988goog.exportProperty(
92989 ol.geom.Point.prototype,
92990 'getKeys',
92991 ol.geom.Point.prototype.getKeys);
92992
92993goog.exportProperty(
92994 ol.geom.Point.prototype,
92995 'getProperties',
92996 ol.geom.Point.prototype.getProperties);
92997
92998goog.exportProperty(
92999 ol.geom.Point.prototype,
93000 'set',
93001 ol.geom.Point.prototype.set);
93002
93003goog.exportProperty(
93004 ol.geom.Point.prototype,
93005 'setProperties',
93006 ol.geom.Point.prototype.setProperties);
93007
93008goog.exportProperty(
93009 ol.geom.Point.prototype,
93010 'unset',
93011 ol.geom.Point.prototype.unset);
93012
93013goog.exportProperty(
93014 ol.geom.Point.prototype,
93015 'changed',
93016 ol.geom.Point.prototype.changed);
93017
93018goog.exportProperty(
93019 ol.geom.Point.prototype,
93020 'dispatchEvent',
93021 ol.geom.Point.prototype.dispatchEvent);
93022
93023goog.exportProperty(
93024 ol.geom.Point.prototype,
93025 'getRevision',
93026 ol.geom.Point.prototype.getRevision);
93027
93028goog.exportProperty(
93029 ol.geom.Point.prototype,
93030 'on',
93031 ol.geom.Point.prototype.on);
93032
93033goog.exportProperty(
93034 ol.geom.Point.prototype,
93035 'once',
93036 ol.geom.Point.prototype.once);
93037
93038goog.exportProperty(
93039 ol.geom.Point.prototype,
93040 'un',
93041 ol.geom.Point.prototype.un);
93042
93043goog.exportProperty(
93044 ol.geom.Polygon.prototype,
93045 'getFirstCoordinate',
93046 ol.geom.Polygon.prototype.getFirstCoordinate);
93047
93048goog.exportProperty(
93049 ol.geom.Polygon.prototype,
93050 'getLastCoordinate',
93051 ol.geom.Polygon.prototype.getLastCoordinate);
93052
93053goog.exportProperty(
93054 ol.geom.Polygon.prototype,
93055 'getLayout',
93056 ol.geom.Polygon.prototype.getLayout);
93057
93058goog.exportProperty(
93059 ol.geom.Polygon.prototype,
93060 'rotate',
93061 ol.geom.Polygon.prototype.rotate);
93062
93063goog.exportProperty(
93064 ol.geom.Polygon.prototype,
93065 'scale',
93066 ol.geom.Polygon.prototype.scale);
93067
93068goog.exportProperty(
93069 ol.geom.Polygon.prototype,
93070 'getClosestPoint',
93071 ol.geom.Polygon.prototype.getClosestPoint);
93072
93073goog.exportProperty(
93074 ol.geom.Polygon.prototype,
93075 'intersectsCoordinate',
93076 ol.geom.Polygon.prototype.intersectsCoordinate);
93077
93078goog.exportProperty(
93079 ol.geom.Polygon.prototype,
93080 'getExtent',
93081 ol.geom.Polygon.prototype.getExtent);
93082
93083goog.exportProperty(
93084 ol.geom.Polygon.prototype,
93085 'simplify',
93086 ol.geom.Polygon.prototype.simplify);
93087
93088goog.exportProperty(
93089 ol.geom.Polygon.prototype,
93090 'transform',
93091 ol.geom.Polygon.prototype.transform);
93092
93093goog.exportProperty(
93094 ol.geom.Polygon.prototype,
93095 'get',
93096 ol.geom.Polygon.prototype.get);
93097
93098goog.exportProperty(
93099 ol.geom.Polygon.prototype,
93100 'getKeys',
93101 ol.geom.Polygon.prototype.getKeys);
93102
93103goog.exportProperty(
93104 ol.geom.Polygon.prototype,
93105 'getProperties',
93106 ol.geom.Polygon.prototype.getProperties);
93107
93108goog.exportProperty(
93109 ol.geom.Polygon.prototype,
93110 'set',
93111 ol.geom.Polygon.prototype.set);
93112
93113goog.exportProperty(
93114 ol.geom.Polygon.prototype,
93115 'setProperties',
93116 ol.geom.Polygon.prototype.setProperties);
93117
93118goog.exportProperty(
93119 ol.geom.Polygon.prototype,
93120 'unset',
93121 ol.geom.Polygon.prototype.unset);
93122
93123goog.exportProperty(
93124 ol.geom.Polygon.prototype,
93125 'changed',
93126 ol.geom.Polygon.prototype.changed);
93127
93128goog.exportProperty(
93129 ol.geom.Polygon.prototype,
93130 'dispatchEvent',
93131 ol.geom.Polygon.prototype.dispatchEvent);
93132
93133goog.exportProperty(
93134 ol.geom.Polygon.prototype,
93135 'getRevision',
93136 ol.geom.Polygon.prototype.getRevision);
93137
93138goog.exportProperty(
93139 ol.geom.Polygon.prototype,
93140 'on',
93141 ol.geom.Polygon.prototype.on);
93142
93143goog.exportProperty(
93144 ol.geom.Polygon.prototype,
93145 'once',
93146 ol.geom.Polygon.prototype.once);
93147
93148goog.exportProperty(
93149 ol.geom.Polygon.prototype,
93150 'un',
93151 ol.geom.Polygon.prototype.un);
93152
93153goog.exportProperty(
93154 ol.format.GML.prototype,
93155 'readFeatures',
93156 ol.format.GML.prototype.readFeatures);
93157
93158goog.exportProperty(
93159 ol.format.GML2.prototype,
93160 'readFeatures',
93161 ol.format.GML2.prototype.readFeatures);
93162
93163goog.exportProperty(
93164 ol.format.GML3.prototype,
93165 'readFeatures',
93166 ol.format.GML3.prototype.readFeatures);
93167
93168goog.exportProperty(
93169 ol.control.Control.prototype,
93170 'get',
93171 ol.control.Control.prototype.get);
93172
93173goog.exportProperty(
93174 ol.control.Control.prototype,
93175 'getKeys',
93176 ol.control.Control.prototype.getKeys);
93177
93178goog.exportProperty(
93179 ol.control.Control.prototype,
93180 'getProperties',
93181 ol.control.Control.prototype.getProperties);
93182
93183goog.exportProperty(
93184 ol.control.Control.prototype,
93185 'set',
93186 ol.control.Control.prototype.set);
93187
93188goog.exportProperty(
93189 ol.control.Control.prototype,
93190 'setProperties',
93191 ol.control.Control.prototype.setProperties);
93192
93193goog.exportProperty(
93194 ol.control.Control.prototype,
93195 'unset',
93196 ol.control.Control.prototype.unset);
93197
93198goog.exportProperty(
93199 ol.control.Control.prototype,
93200 'changed',
93201 ol.control.Control.prototype.changed);
93202
93203goog.exportProperty(
93204 ol.control.Control.prototype,
93205 'dispatchEvent',
93206 ol.control.Control.prototype.dispatchEvent);
93207
93208goog.exportProperty(
93209 ol.control.Control.prototype,
93210 'getRevision',
93211 ol.control.Control.prototype.getRevision);
93212
93213goog.exportProperty(
93214 ol.control.Control.prototype,
93215 'on',
93216 ol.control.Control.prototype.on);
93217
93218goog.exportProperty(
93219 ol.control.Control.prototype,
93220 'once',
93221 ol.control.Control.prototype.once);
93222
93223goog.exportProperty(
93224 ol.control.Control.prototype,
93225 'un',
93226 ol.control.Control.prototype.un);
93227
93228goog.exportProperty(
93229 ol.control.Attribution.prototype,
93230 'getMap',
93231 ol.control.Attribution.prototype.getMap);
93232
93233goog.exportProperty(
93234 ol.control.Attribution.prototype,
93235 'setMap',
93236 ol.control.Attribution.prototype.setMap);
93237
93238goog.exportProperty(
93239 ol.control.Attribution.prototype,
93240 'setTarget',
93241 ol.control.Attribution.prototype.setTarget);
93242
93243goog.exportProperty(
93244 ol.control.Attribution.prototype,
93245 'get',
93246 ol.control.Attribution.prototype.get);
93247
93248goog.exportProperty(
93249 ol.control.Attribution.prototype,
93250 'getKeys',
93251 ol.control.Attribution.prototype.getKeys);
93252
93253goog.exportProperty(
93254 ol.control.Attribution.prototype,
93255 'getProperties',
93256 ol.control.Attribution.prototype.getProperties);
93257
93258goog.exportProperty(
93259 ol.control.Attribution.prototype,
93260 'set',
93261 ol.control.Attribution.prototype.set);
93262
93263goog.exportProperty(
93264 ol.control.Attribution.prototype,
93265 'setProperties',
93266 ol.control.Attribution.prototype.setProperties);
93267
93268goog.exportProperty(
93269 ol.control.Attribution.prototype,
93270 'unset',
93271 ol.control.Attribution.prototype.unset);
93272
93273goog.exportProperty(
93274 ol.control.Attribution.prototype,
93275 'changed',
93276 ol.control.Attribution.prototype.changed);
93277
93278goog.exportProperty(
93279 ol.control.Attribution.prototype,
93280 'dispatchEvent',
93281 ol.control.Attribution.prototype.dispatchEvent);
93282
93283goog.exportProperty(
93284 ol.control.Attribution.prototype,
93285 'getRevision',
93286 ol.control.Attribution.prototype.getRevision);
93287
93288goog.exportProperty(
93289 ol.control.Attribution.prototype,
93290 'on',
93291 ol.control.Attribution.prototype.on);
93292
93293goog.exportProperty(
93294 ol.control.Attribution.prototype,
93295 'once',
93296 ol.control.Attribution.prototype.once);
93297
93298goog.exportProperty(
93299 ol.control.Attribution.prototype,
93300 'un',
93301 ol.control.Attribution.prototype.un);
93302
93303goog.exportProperty(
93304 ol.control.FullScreen.prototype,
93305 'getMap',
93306 ol.control.FullScreen.prototype.getMap);
93307
93308goog.exportProperty(
93309 ol.control.FullScreen.prototype,
93310 'setMap',
93311 ol.control.FullScreen.prototype.setMap);
93312
93313goog.exportProperty(
93314 ol.control.FullScreen.prototype,
93315 'setTarget',
93316 ol.control.FullScreen.prototype.setTarget);
93317
93318goog.exportProperty(
93319 ol.control.FullScreen.prototype,
93320 'get',
93321 ol.control.FullScreen.prototype.get);
93322
93323goog.exportProperty(
93324 ol.control.FullScreen.prototype,
93325 'getKeys',
93326 ol.control.FullScreen.prototype.getKeys);
93327
93328goog.exportProperty(
93329 ol.control.FullScreen.prototype,
93330 'getProperties',
93331 ol.control.FullScreen.prototype.getProperties);
93332
93333goog.exportProperty(
93334 ol.control.FullScreen.prototype,
93335 'set',
93336 ol.control.FullScreen.prototype.set);
93337
93338goog.exportProperty(
93339 ol.control.FullScreen.prototype,
93340 'setProperties',
93341 ol.control.FullScreen.prototype.setProperties);
93342
93343goog.exportProperty(
93344 ol.control.FullScreen.prototype,
93345 'unset',
93346 ol.control.FullScreen.prototype.unset);
93347
93348goog.exportProperty(
93349 ol.control.FullScreen.prototype,
93350 'changed',
93351 ol.control.FullScreen.prototype.changed);
93352
93353goog.exportProperty(
93354 ol.control.FullScreen.prototype,
93355 'dispatchEvent',
93356 ol.control.FullScreen.prototype.dispatchEvent);
93357
93358goog.exportProperty(
93359 ol.control.FullScreen.prototype,
93360 'getRevision',
93361 ol.control.FullScreen.prototype.getRevision);
93362
93363goog.exportProperty(
93364 ol.control.FullScreen.prototype,
93365 'on',
93366 ol.control.FullScreen.prototype.on);
93367
93368goog.exportProperty(
93369 ol.control.FullScreen.prototype,
93370 'once',
93371 ol.control.FullScreen.prototype.once);
93372
93373goog.exportProperty(
93374 ol.control.FullScreen.prototype,
93375 'un',
93376 ol.control.FullScreen.prototype.un);
93377
93378goog.exportProperty(
93379 ol.control.MousePosition.prototype,
93380 'getMap',
93381 ol.control.MousePosition.prototype.getMap);
93382
93383goog.exportProperty(
93384 ol.control.MousePosition.prototype,
93385 'setMap',
93386 ol.control.MousePosition.prototype.setMap);
93387
93388goog.exportProperty(
93389 ol.control.MousePosition.prototype,
93390 'setTarget',
93391 ol.control.MousePosition.prototype.setTarget);
93392
93393goog.exportProperty(
93394 ol.control.MousePosition.prototype,
93395 'get',
93396 ol.control.MousePosition.prototype.get);
93397
93398goog.exportProperty(
93399 ol.control.MousePosition.prototype,
93400 'getKeys',
93401 ol.control.MousePosition.prototype.getKeys);
93402
93403goog.exportProperty(
93404 ol.control.MousePosition.prototype,
93405 'getProperties',
93406 ol.control.MousePosition.prototype.getProperties);
93407
93408goog.exportProperty(
93409 ol.control.MousePosition.prototype,
93410 'set',
93411 ol.control.MousePosition.prototype.set);
93412
93413goog.exportProperty(
93414 ol.control.MousePosition.prototype,
93415 'setProperties',
93416 ol.control.MousePosition.prototype.setProperties);
93417
93418goog.exportProperty(
93419 ol.control.MousePosition.prototype,
93420 'unset',
93421 ol.control.MousePosition.prototype.unset);
93422
93423goog.exportProperty(
93424 ol.control.MousePosition.prototype,
93425 'changed',
93426 ol.control.MousePosition.prototype.changed);
93427
93428goog.exportProperty(
93429 ol.control.MousePosition.prototype,
93430 'dispatchEvent',
93431 ol.control.MousePosition.prototype.dispatchEvent);
93432
93433goog.exportProperty(
93434 ol.control.MousePosition.prototype,
93435 'getRevision',
93436 ol.control.MousePosition.prototype.getRevision);
93437
93438goog.exportProperty(
93439 ol.control.MousePosition.prototype,
93440 'on',
93441 ol.control.MousePosition.prototype.on);
93442
93443goog.exportProperty(
93444 ol.control.MousePosition.prototype,
93445 'once',
93446 ol.control.MousePosition.prototype.once);
93447
93448goog.exportProperty(
93449 ol.control.MousePosition.prototype,
93450 'un',
93451 ol.control.MousePosition.prototype.un);
93452
93453goog.exportProperty(
93454 ol.control.OverviewMap.prototype,
93455 'getMap',
93456 ol.control.OverviewMap.prototype.getMap);
93457
93458goog.exportProperty(
93459 ol.control.OverviewMap.prototype,
93460 'setMap',
93461 ol.control.OverviewMap.prototype.setMap);
93462
93463goog.exportProperty(
93464 ol.control.OverviewMap.prototype,
93465 'setTarget',
93466 ol.control.OverviewMap.prototype.setTarget);
93467
93468goog.exportProperty(
93469 ol.control.OverviewMap.prototype,
93470 'get',
93471 ol.control.OverviewMap.prototype.get);
93472
93473goog.exportProperty(
93474 ol.control.OverviewMap.prototype,
93475 'getKeys',
93476 ol.control.OverviewMap.prototype.getKeys);
93477
93478goog.exportProperty(
93479 ol.control.OverviewMap.prototype,
93480 'getProperties',
93481 ol.control.OverviewMap.prototype.getProperties);
93482
93483goog.exportProperty(
93484 ol.control.OverviewMap.prototype,
93485 'set',
93486 ol.control.OverviewMap.prototype.set);
93487
93488goog.exportProperty(
93489 ol.control.OverviewMap.prototype,
93490 'setProperties',
93491 ol.control.OverviewMap.prototype.setProperties);
93492
93493goog.exportProperty(
93494 ol.control.OverviewMap.prototype,
93495 'unset',
93496 ol.control.OverviewMap.prototype.unset);
93497
93498goog.exportProperty(
93499 ol.control.OverviewMap.prototype,
93500 'changed',
93501 ol.control.OverviewMap.prototype.changed);
93502
93503goog.exportProperty(
93504 ol.control.OverviewMap.prototype,
93505 'dispatchEvent',
93506 ol.control.OverviewMap.prototype.dispatchEvent);
93507
93508goog.exportProperty(
93509 ol.control.OverviewMap.prototype,
93510 'getRevision',
93511 ol.control.OverviewMap.prototype.getRevision);
93512
93513goog.exportProperty(
93514 ol.control.OverviewMap.prototype,
93515 'on',
93516 ol.control.OverviewMap.prototype.on);
93517
93518goog.exportProperty(
93519 ol.control.OverviewMap.prototype,
93520 'once',
93521 ol.control.OverviewMap.prototype.once);
93522
93523goog.exportProperty(
93524 ol.control.OverviewMap.prototype,
93525 'un',
93526 ol.control.OverviewMap.prototype.un);
93527
93528goog.exportProperty(
93529 ol.control.Rotate.prototype,
93530 'getMap',
93531 ol.control.Rotate.prototype.getMap);
93532
93533goog.exportProperty(
93534 ol.control.Rotate.prototype,
93535 'setMap',
93536 ol.control.Rotate.prototype.setMap);
93537
93538goog.exportProperty(
93539 ol.control.Rotate.prototype,
93540 'setTarget',
93541 ol.control.Rotate.prototype.setTarget);
93542
93543goog.exportProperty(
93544 ol.control.Rotate.prototype,
93545 'get',
93546 ol.control.Rotate.prototype.get);
93547
93548goog.exportProperty(
93549 ol.control.Rotate.prototype,
93550 'getKeys',
93551 ol.control.Rotate.prototype.getKeys);
93552
93553goog.exportProperty(
93554 ol.control.Rotate.prototype,
93555 'getProperties',
93556 ol.control.Rotate.prototype.getProperties);
93557
93558goog.exportProperty(
93559 ol.control.Rotate.prototype,
93560 'set',
93561 ol.control.Rotate.prototype.set);
93562
93563goog.exportProperty(
93564 ol.control.Rotate.prototype,
93565 'setProperties',
93566 ol.control.Rotate.prototype.setProperties);
93567
93568goog.exportProperty(
93569 ol.control.Rotate.prototype,
93570 'unset',
93571 ol.control.Rotate.prototype.unset);
93572
93573goog.exportProperty(
93574 ol.control.Rotate.prototype,
93575 'changed',
93576 ol.control.Rotate.prototype.changed);
93577
93578goog.exportProperty(
93579 ol.control.Rotate.prototype,
93580 'dispatchEvent',
93581 ol.control.Rotate.prototype.dispatchEvent);
93582
93583goog.exportProperty(
93584 ol.control.Rotate.prototype,
93585 'getRevision',
93586 ol.control.Rotate.prototype.getRevision);
93587
93588goog.exportProperty(
93589 ol.control.Rotate.prototype,
93590 'on',
93591 ol.control.Rotate.prototype.on);
93592
93593goog.exportProperty(
93594 ol.control.Rotate.prototype,
93595 'once',
93596 ol.control.Rotate.prototype.once);
93597
93598goog.exportProperty(
93599 ol.control.Rotate.prototype,
93600 'un',
93601 ol.control.Rotate.prototype.un);
93602
93603goog.exportProperty(
93604 ol.control.ScaleLine.prototype,
93605 'getMap',
93606 ol.control.ScaleLine.prototype.getMap);
93607
93608goog.exportProperty(
93609 ol.control.ScaleLine.prototype,
93610 'setMap',
93611 ol.control.ScaleLine.prototype.setMap);
93612
93613goog.exportProperty(
93614 ol.control.ScaleLine.prototype,
93615 'setTarget',
93616 ol.control.ScaleLine.prototype.setTarget);
93617
93618goog.exportProperty(
93619 ol.control.ScaleLine.prototype,
93620 'get',
93621 ol.control.ScaleLine.prototype.get);
93622
93623goog.exportProperty(
93624 ol.control.ScaleLine.prototype,
93625 'getKeys',
93626 ol.control.ScaleLine.prototype.getKeys);
93627
93628goog.exportProperty(
93629 ol.control.ScaleLine.prototype,
93630 'getProperties',
93631 ol.control.ScaleLine.prototype.getProperties);
93632
93633goog.exportProperty(
93634 ol.control.ScaleLine.prototype,
93635 'set',
93636 ol.control.ScaleLine.prototype.set);
93637
93638goog.exportProperty(
93639 ol.control.ScaleLine.prototype,
93640 'setProperties',
93641 ol.control.ScaleLine.prototype.setProperties);
93642
93643goog.exportProperty(
93644 ol.control.ScaleLine.prototype,
93645 'unset',
93646 ol.control.ScaleLine.prototype.unset);
93647
93648goog.exportProperty(
93649 ol.control.ScaleLine.prototype,
93650 'changed',
93651 ol.control.ScaleLine.prototype.changed);
93652
93653goog.exportProperty(
93654 ol.control.ScaleLine.prototype,
93655 'dispatchEvent',
93656 ol.control.ScaleLine.prototype.dispatchEvent);
93657
93658goog.exportProperty(
93659 ol.control.ScaleLine.prototype,
93660 'getRevision',
93661 ol.control.ScaleLine.prototype.getRevision);
93662
93663goog.exportProperty(
93664 ol.control.ScaleLine.prototype,
93665 'on',
93666 ol.control.ScaleLine.prototype.on);
93667
93668goog.exportProperty(
93669 ol.control.ScaleLine.prototype,
93670 'once',
93671 ol.control.ScaleLine.prototype.once);
93672
93673goog.exportProperty(
93674 ol.control.ScaleLine.prototype,
93675 'un',
93676 ol.control.ScaleLine.prototype.un);
93677
93678goog.exportProperty(
93679 ol.control.Zoom.prototype,
93680 'getMap',
93681 ol.control.Zoom.prototype.getMap);
93682
93683goog.exportProperty(
93684 ol.control.Zoom.prototype,
93685 'setMap',
93686 ol.control.Zoom.prototype.setMap);
93687
93688goog.exportProperty(
93689 ol.control.Zoom.prototype,
93690 'setTarget',
93691 ol.control.Zoom.prototype.setTarget);
93692
93693goog.exportProperty(
93694 ol.control.Zoom.prototype,
93695 'get',
93696 ol.control.Zoom.prototype.get);
93697
93698goog.exportProperty(
93699 ol.control.Zoom.prototype,
93700 'getKeys',
93701 ol.control.Zoom.prototype.getKeys);
93702
93703goog.exportProperty(
93704 ol.control.Zoom.prototype,
93705 'getProperties',
93706 ol.control.Zoom.prototype.getProperties);
93707
93708goog.exportProperty(
93709 ol.control.Zoom.prototype,
93710 'set',
93711 ol.control.Zoom.prototype.set);
93712
93713goog.exportProperty(
93714 ol.control.Zoom.prototype,
93715 'setProperties',
93716 ol.control.Zoom.prototype.setProperties);
93717
93718goog.exportProperty(
93719 ol.control.Zoom.prototype,
93720 'unset',
93721 ol.control.Zoom.prototype.unset);
93722
93723goog.exportProperty(
93724 ol.control.Zoom.prototype,
93725 'changed',
93726 ol.control.Zoom.prototype.changed);
93727
93728goog.exportProperty(
93729 ol.control.Zoom.prototype,
93730 'dispatchEvent',
93731 ol.control.Zoom.prototype.dispatchEvent);
93732
93733goog.exportProperty(
93734 ol.control.Zoom.prototype,
93735 'getRevision',
93736 ol.control.Zoom.prototype.getRevision);
93737
93738goog.exportProperty(
93739 ol.control.Zoom.prototype,
93740 'on',
93741 ol.control.Zoom.prototype.on);
93742
93743goog.exportProperty(
93744 ol.control.Zoom.prototype,
93745 'once',
93746 ol.control.Zoom.prototype.once);
93747
93748goog.exportProperty(
93749 ol.control.Zoom.prototype,
93750 'un',
93751 ol.control.Zoom.prototype.un);
93752
93753goog.exportProperty(
93754 ol.control.ZoomSlider.prototype,
93755 'getMap',
93756 ol.control.ZoomSlider.prototype.getMap);
93757
93758goog.exportProperty(
93759 ol.control.ZoomSlider.prototype,
93760 'setMap',
93761 ol.control.ZoomSlider.prototype.setMap);
93762
93763goog.exportProperty(
93764 ol.control.ZoomSlider.prototype,
93765 'setTarget',
93766 ol.control.ZoomSlider.prototype.setTarget);
93767
93768goog.exportProperty(
93769 ol.control.ZoomSlider.prototype,
93770 'get',
93771 ol.control.ZoomSlider.prototype.get);
93772
93773goog.exportProperty(
93774 ol.control.ZoomSlider.prototype,
93775 'getKeys',
93776 ol.control.ZoomSlider.prototype.getKeys);
93777
93778goog.exportProperty(
93779 ol.control.ZoomSlider.prototype,
93780 'getProperties',
93781 ol.control.ZoomSlider.prototype.getProperties);
93782
93783goog.exportProperty(
93784 ol.control.ZoomSlider.prototype,
93785 'set',
93786 ol.control.ZoomSlider.prototype.set);
93787
93788goog.exportProperty(
93789 ol.control.ZoomSlider.prototype,
93790 'setProperties',
93791 ol.control.ZoomSlider.prototype.setProperties);
93792
93793goog.exportProperty(
93794 ol.control.ZoomSlider.prototype,
93795 'unset',
93796 ol.control.ZoomSlider.prototype.unset);
93797
93798goog.exportProperty(
93799 ol.control.ZoomSlider.prototype,
93800 'changed',
93801 ol.control.ZoomSlider.prototype.changed);
93802
93803goog.exportProperty(
93804 ol.control.ZoomSlider.prototype,
93805 'dispatchEvent',
93806 ol.control.ZoomSlider.prototype.dispatchEvent);
93807
93808goog.exportProperty(
93809 ol.control.ZoomSlider.prototype,
93810 'getRevision',
93811 ol.control.ZoomSlider.prototype.getRevision);
93812
93813goog.exportProperty(
93814 ol.control.ZoomSlider.prototype,
93815 'on',
93816 ol.control.ZoomSlider.prototype.on);
93817
93818goog.exportProperty(
93819 ol.control.ZoomSlider.prototype,
93820 'once',
93821 ol.control.ZoomSlider.prototype.once);
93822
93823goog.exportProperty(
93824 ol.control.ZoomSlider.prototype,
93825 'un',
93826 ol.control.ZoomSlider.prototype.un);
93827
93828goog.exportProperty(
93829 ol.control.ZoomToExtent.prototype,
93830 'getMap',
93831 ol.control.ZoomToExtent.prototype.getMap);
93832
93833goog.exportProperty(
93834 ol.control.ZoomToExtent.prototype,
93835 'setMap',
93836 ol.control.ZoomToExtent.prototype.setMap);
93837
93838goog.exportProperty(
93839 ol.control.ZoomToExtent.prototype,
93840 'setTarget',
93841 ol.control.ZoomToExtent.prototype.setTarget);
93842
93843goog.exportProperty(
93844 ol.control.ZoomToExtent.prototype,
93845 'get',
93846 ol.control.ZoomToExtent.prototype.get);
93847
93848goog.exportProperty(
93849 ol.control.ZoomToExtent.prototype,
93850 'getKeys',
93851 ol.control.ZoomToExtent.prototype.getKeys);
93852
93853goog.exportProperty(
93854 ol.control.ZoomToExtent.prototype,
93855 'getProperties',
93856 ol.control.ZoomToExtent.prototype.getProperties);
93857
93858goog.exportProperty(
93859 ol.control.ZoomToExtent.prototype,
93860 'set',
93861 ol.control.ZoomToExtent.prototype.set);
93862
93863goog.exportProperty(
93864 ol.control.ZoomToExtent.prototype,
93865 'setProperties',
93866 ol.control.ZoomToExtent.prototype.setProperties);
93867
93868goog.exportProperty(
93869 ol.control.ZoomToExtent.prototype,
93870 'unset',
93871 ol.control.ZoomToExtent.prototype.unset);
93872
93873goog.exportProperty(
93874 ol.control.ZoomToExtent.prototype,
93875 'changed',
93876 ol.control.ZoomToExtent.prototype.changed);
93877
93878goog.exportProperty(
93879 ol.control.ZoomToExtent.prototype,
93880 'dispatchEvent',
93881 ol.control.ZoomToExtent.prototype.dispatchEvent);
93882
93883goog.exportProperty(
93884 ol.control.ZoomToExtent.prototype,
93885 'getRevision',
93886 ol.control.ZoomToExtent.prototype.getRevision);
93887
93888goog.exportProperty(
93889 ol.control.ZoomToExtent.prototype,
93890 'on',
93891 ol.control.ZoomToExtent.prototype.on);
93892
93893goog.exportProperty(
93894 ol.control.ZoomToExtent.prototype,
93895 'once',
93896 ol.control.ZoomToExtent.prototype.once);
93897
93898goog.exportProperty(
93899 ol.control.ZoomToExtent.prototype,
93900 'un',
93901 ol.control.ZoomToExtent.prototype.un);
93902ol.VERSION = 'v4.3.2';
93903OPENLAYERS.ol = ol;
93904
93905 return OPENLAYERS.ol;
93906}));